package cn.iocoder.yudao.module.system.service.user;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.infra.api.config.ConfigApi;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthRegisterReqVO;
import cn.iocoder.yudao.module.system.controller.admin.gugu.gugu.CollegeEnrollmentPlanInfo;
import cn.iocoder.yudao.module.system.controller.admin.gugu.gugu.MajorAdmissionInfo;
import cn.iocoder.yudao.module.system.controller.admin.gugu.vo.CeeMajorTreeVO;
import cn.iocoder.yudao.module.system.dal.dataobject.collegeenrollmentplan.CollegeEnrollmentPlanDO;
import cn.iocoder.yudao.module.system.dal.dataobject.gugu.CeeMajorDO;
import cn.iocoder.yudao.module.system.dal.dataobject.gugu.MajorAdmissionDO;
import cn.iocoder.yudao.module.system.dal.dataobject.gugu.ScoreSegmentDO;
import cn.iocoder.yudao.module.system.service.gugu.CeeMajorService;
import cn.iocoder.yudao.module.system.service.gugu.CollegeEnrollmentPlanService;
import cn.iocoder.yudao.module.system.dal.mysql.collegeenrollmentplan.CollegeEnrollmentPlanMapper;
import cn.iocoder.yudao.module.system.dal.mysql.gugu.MajorAdmissionMapper;

import java.util.stream.Collectors;

import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.scores.UserScoresSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportExcelVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportRespVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.answerRecord.AnswerRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.answerRecord.AnswerRecordMapper;
import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dept.PostService;
import cn.iocoder.yudao.module.system.service.gugu.MajorAdmissionService;
import cn.iocoder.yudao.module.system.service.gugu.ScoreSegmentService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import cn.iocoder.yudao.module.system.util.PerformanceMonitor;
import cn.iocoder.yudao.module.system.util.SubjectSelectionUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.annotations.VisibleForTesting;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.service.impl.DiffParseFunction;
import com.mzt.logapi.starter.annotation.LogRecord;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PreDestroy;

import javax.annotation.Resource;
import javax.validation.ConstraintViolationException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;

/**
 * 后台用户 Service 实现类
 *
 * @author 芋道源码
 */
@Service("adminUserService")
@Slf4j
public class AdminUserServiceImpl implements AdminUserService {

    /**
     * 专业信息类，用于构建树形结构
     */
    @Data
    private static class MajorInfo {
        private Long id;
        private String name;
        private String code;
        private String educationLevel; // 教育级别
        private Boolean isRecommended; // 是否推荐专业
        private String careerDirection; // 就业方向
        private String majorIntroduction; // 专业介绍
        private String graduateScale; // 毕业规模
        private String maleFemaleRatio; // 男女比例
        private List<String> recommendSchools; // 推荐院校
        private List<CeeMajorDO.Course> courses; // 开设课程
    }

    static final String USER_INIT_PASSWORD_KEY = "system.user.init-password";

    /**
     * 用于异步获取排名信息的线程池
     */
    private static final ExecutorService RANKING_EXECUTOR = Executors.newCachedThreadPool(r -> {
        Thread thread = new Thread(r, "ranking-thread");
        thread.setDaemon(true); // 设置为守护线程，不阻止JVM退出
        return thread;
    });

    /**
     * 用户ID到排名查询任务的映射，用于取消正在进行的任务
     */
    private static final ConcurrentHashMap<Long, Future<?>> RANKING_TASKS = new ConcurrentHashMap<>();

    /**
     * 用于异步获取专业推荐的线程池
     */
    private static final ThreadPoolExecutor MAJOR_RECOMMENDATION_EXECUTOR;

    /**
     * 用户ID到专业推荐任务的映射，用于取消正在进行的任务
     */
    private static final ConcurrentHashMap<Long, Future<?>> MAJOR_RECOMMENDATION_TASKS = new ConcurrentHashMap<>();

    static {
        // 获取CPU核心数
        int cpuCores = Runtime.getRuntime().availableProcessors();

        // 配置专业推荐线程池 - 优化为优先执行模式
        // 增加核心线程数以减少排队，使用SynchronousQueue确保任务立即执行
        int corePoolSize = Math.max(4, cpuCores); // 增加核心线程数
        int maximumPoolSize = Math.max(8, cpuCores * 2); // 增加最大线程数

        MAJOR_RECOMMENDATION_EXECUTOR = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                30L, // 减少空闲线程存活时间
                TimeUnit.SECONDS,
                new SynchronousQueue<>(), // 使用SynchronousQueue，不缓存任务，强制立即执行
                r -> {
                    Thread t = new Thread(r, "major-recommendation-" + r.hashCode());
                    t.setDaemon(true);
                    t.setPriority(Thread.NORM_PRIORITY + 1); // 设置稍高优先级
                    t.setUncaughtExceptionHandler((thread, ex) -> {
                        log.error("专业推荐线程[{}]发生未捕获异常: {}", thread.getName(), ex.getMessage(), ex);
                    });
                    return t;
                },
                new ThreadPoolExecutor.CallerRunsPolicy() // 如果线程池满了，在调用者线程中执行
        );

        log.info("初始化专业推荐线程池完成: 核心线程数[{}], 最大线程数[{}], 队列类型[SynchronousQueue]",
                corePoolSize, maximumPoolSize);
    }

    @Resource
    private AdminUserMapper userMapper;

    @Resource
    private DeptService deptService;
    @Resource
    private PostService postService;
    @Resource
    private PermissionService permissionService;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    @Lazy // 延迟，避免循环依赖报错
    private TenantService tenantService;

    @Resource
    private UserPostMapper userPostMapper;

    @Resource
    private FileApi fileApi;
    @Resource
    private ConfigApi configApi;

    @Resource
    private CeeMajorService ceeMajorService;

    @Resource
    private MajorAdmissionService majorAdmissionService;

    @Resource
    private ScoreSegmentService scoreSegmentService;

    @Resource
    private AnswerRecordMapper answerRecordMapper;

    @Resource
    private UserScoresService userScoresService;

    @Resource
    private CollegeEnrollmentPlanService collegeEnrollmentPlanService;

    @Resource
    private CollegeEnrollmentPlanMapper collegeEnrollmentPlanMapper;

    @Resource
    private MajorAdmissionMapper majorAdmissionMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}",
            success = SYSTEM_USER_CREATE_SUCCESS)
    public Long createUser(UserSaveReqVO createReqVO) {
        // 1.1 校验账户配合
        tenantService.handleTenantInfo(tenant -> {
            long count = userMapper.selectCount();
            if (count >= tenant.getAccountCount()) {
                throw exception(USER_COUNT_MAX, tenant.getAccountCount());
            }
        });
        // 1.2 校验正确性
        validateUserForCreateOrUpdate(null, createReqVO.getUsername(),
                createReqVO.getMobile(), createReqVO.getEmail(), createReqVO.getDeptId(), createReqVO.getPostIds());
        // 2.1 插入用户
        AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class);
        user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
        user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码
        userMapper.insert(user);
        // 2.2 插入关联岗位
        if (CollectionUtil.isNotEmpty(user.getPostIds())) {
            userPostMapper.insertBatch(convertList(user.getPostIds(),
                    postId -> new UserPostDO().setUserId(user.getId()).setPostId(postId)));
        }

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("user", user);
        return user.getId();
    }

    @Override
    public Long registerUser(AuthRegisterReqVO registerReqVO) {
        return registerUser(registerReqVO, null);
    }

    @Override
    public Long registerUser(AuthRegisterReqVO registerReqVO, String openId) {
        // 1.1 校验账户配合
        tenantService.handleTenantInfo(tenant -> {
            long count = userMapper.selectCount();
            if (count >= tenant.getAccountCount()) {
                throw exception(USER_COUNT_MAX, tenant.getAccountCount());
            }
        });
        // 1.2 校验正确性
        validateUserForCreateOrUpdate(null, registerReqVO.getUsername(), null, null, null, null);

        // 2. 插入用户
        AdminUserDO user = BeanUtils.toBean(registerReqVO, AdminUserDO.class);
        user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
        user.setPassword(encodePassword(registerReqVO.getPassword())); // 加密密码

        // 2.1 如果昵称为空，自动生成昵称
        if (StrUtil.isEmpty(user.getNickname())) {
            user.setNickname("用户" + RandomUtil.randomNumbers(8));
        }

        // 2.2 如果提供了openId，设置到用户对象中
        if (StrUtil.isNotEmpty(openId)) {
            user.setOpenId(openId);
        }

        userMapper.insert(user);
        return user.getId();
    }

    @Override
    public Long registerUser(AuthRegisterReqVO registerReqVO, String openId, Integer platform) {
        // 1.1 校验账户配合
        tenantService.handleTenantInfo(tenant -> {
            long count = userMapper.selectCount();
            if (count >= tenant.getAccountCount()) {
                throw exception(USER_COUNT_MAX, tenant.getAccountCount());
            }
        });
        // 1.2 校验正确性
        validateUserForCreateOrUpdate(null, registerReqVO.getUsername(), null, null, null, null);

        // 2. 插入用户
        AdminUserDO user = BeanUtils.toBean(registerReqVO, AdminUserDO.class);
        user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
        user.setPassword(encodePassword(registerReqVO.getPassword())); // 加密密码

        // 2.1 如果昵称为空，自动生成昵称
        if (StrUtil.isEmpty(user.getNickname())) {
            user.setNickname("用户" + RandomUtil.randomNumbers(8));
        }

        // 2.2 如果提供了openId，根据平台类型设置到相应字段中
        if (StrUtil.isNotEmpty(openId)) {
            user.setOpenId(openId); // 保留兼容性
            if (Integer.valueOf(34).equals(platform)) {
                // 微信小程序
                user.setWechatOpenId(openId);
            } else if (Integer.valueOf(40).equals(platform)) {
                // 快手
                user.setKuaishouOpenId(openId);
            }
        }

        userMapper.insert(user);
        return user.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
            success = SYSTEM_USER_UPDATE_SUCCESS)
    public void updateUser(UserSaveReqVO updateReqVO) {
        updateReqVO.setPassword(null); // 特殊：此处不更新密码
        // 1. 校验正确性
        AdminUserDO oldUser = validateUserForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getUsername(),
                updateReqVO.getMobile(), updateReqVO.getEmail(), updateReqVO.getDeptId(), updateReqVO.getPostIds());

        // 1.1 校验分数区间
        validateScoreRange(updateReqVO);

        // 检查影响专业推荐的关键字段是否发生变化
        boolean needRefreshRecommendations = checkIfNeedRefreshRecommendations(updateReqVO, oldUser);

        // 如果关键字段变化，清空推荐专业
        if (needRefreshRecommendations) {
            log.info("User ID {} key fields changed, clearing recommended majors", updateReqVO.getId());
            updateReqVO.setRecommendedMajors("");
        }

        //当还有正在生成中的报告时，不允许修改影响推荐的关键字段
//        if (needRefreshRecommendations && hasGeneratingReport(updateReqVO.getId())) {
//            throw exception(new ErrorCode(400, "当前有正在答题中的报告，请继续完成答题再修改分数、分数区间、省份和选科"));
//        }

        // 2.1 更新用户
        AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class);
        userMapper.updateById(updateObj);

        // 2.2 更新岗位
        updateUserPost(updateReqVO, updateObj);

        // 2.3 当关键字段变化时，重新获取排名信息和专业推荐
        if (needRefreshRecommendations) {
            log.info("User ID {} key fields changed, refreshing ranking and major recommendations", updateReqVO.getId());

            // 同步更新成绩表
            syncUserScores(updateObj);

            // 同步获取排名信息
            getUserRanking(updateObj);

            if (updateObj.getProvince() != null && updateObj.getScore() != null) {
                // 使用优化后的异步专业推荐方法
                asyncGetMajorRecommendations(updateObj);
            }
        }

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldUser, UserSaveReqVO.class));
        LogRecordContext.putVariable("user", oldUser);
    }

    /**
     * 优化后的异步获取专业推荐方法
     */
    private void asyncGetMajorRecommendations(AdminUserDO user) {
        final Long userId = user.getId();
        final String province = user.getProvince();
        final Double userScore = user.getScore();
        final String secondSubject = user.getSecondSubject();

        // 取消之前的任务（如果存在）
        Future<?> previousTask = MAJOR_RECOMMENDATION_TASKS.get(userId);
        if (previousTask != null && !previousTask.isDone()) {
            log.info("取消用户ID {}的上一个专业推荐任务", userId);
            previousTask.cancel(true);
        }

        // 创建新的任务
        Future<?> task = MAJOR_RECOMMENDATION_EXECUTOR.submit(() -> {
            try {
                // 检查任务是否被取消
                if (Thread.currentThread().isInterrupted()) {
                    log.info("用户ID {}的专业推荐任务在开始前被取消", userId);
                    return;
                }

                long startTime = System.currentTimeMillis();
                log.info("开始为用户ID {}异步获取专业推荐", userId);

                // 获取用户的选科信息
                final Set<String> userSubjects = parseUserSubjects(secondSubject);
                log.info("用户ID {}的选科信息: {}", userId, userSubjects);

                // 设置分数范围 - 从用户设置的字段获取，如果没有设置则使用默认值
                int score = userScore.intValue();
                int minScore;
                int maxScore;

                if (user.getMinScore() != null) {
                    minScore = user.getMinScore().intValue();
                    log.info("用户ID {}使用自定义最低分数: {}", userId, minScore);
                } else {
                    minScore = score - 50; // 默认值：用户分数减50
                    log.info("用户ID {}使用默认最低分数: {} (用户分数-50)", userId, minScore);
                }

                if (user.getMaxScore() != null) {
                    maxScore = user.getMaxScore().intValue();
                    log.info("用户ID {}使用自定义最高分数: {}", userId, maxScore);
                } else {
                    maxScore = score + 10; // 默认值：用户分数加10
                    log.info("用户ID {}使用默认最高分数: {} (用户分数+10)", userId, maxScore);
                }

                // 获取用户的选科类型
                String typeName = user.getTypeName();
                if (typeName == null || typeName.isEmpty()) {
                    typeName = determineSubjectSelection(province, secondSubject);
                    log.info("用户ID {}未设置选科类型，根据省份{}和选科{}确定为{}", userId, province, secondSubject, typeName);

                    // 更新用户的选科类型字段
                    AdminUserDO typeUpdateObj = new AdminUserDO();
                    typeUpdateObj.setId(userId);
                    typeUpdateObj.setTypeName(typeName);
                    userMapper.updateById(typeUpdateObj);
                }

                // 检查任务是否被取消
                if (Thread.currentThread().isInterrupted()) {
                    log.info("用户ID {}的专业推荐任务在数据查询前被取消", userId);
                    return;
                }

                // 第一步：根据专业录取分数线筛选
                List<MajorAdmissionInfo> admissionList = queryAdmissionScoresByScoreRangeForUser(province, minScore, maxScore, typeName);
                log.info("第一步：为用户ID {}根据专业录取分数线筛选得到 {} 条数据", userId, admissionList.size());

                if (admissionList.isEmpty()) {
                    log.warn("用户ID {}未找到符合分数条件的专业录取数据", userId);
                    saveNoRecommendationResult(userId);
                    return;
                }

                // 检查任务是否被取消
                if (Thread.currentThread().isInterrupted()) {
                    log.info("用户ID {}的专业推荐任务在招生计划筛选前被取消", userId);
                    return;
                }

                // 第二步：根据招生计划筛选
                List<MajorAdmissionInfo> filteredAdmissionList = filterAdmissionsByEnrollmentPlansForUser(admissionList, province, userSubjects, typeName);
                log.info("第二步：为用户ID {}根据招生计划筛选得到 {} 条数据", userId, filteredAdmissionList.size());

                if (filteredAdmissionList.isEmpty()) {
                    log.warn("用户ID {}未找到符合条件的专业录取数据", userId);
                    saveNoRecommendationResult(userId);
                    return;
                }

                // 检查任务是否被取消
                if (Thread.currentThread().isInterrupted()) {
                    log.info("用户ID {}的专业推荐任务在专业信息查询前被取消", userId);
                    return;
                }

                // 优化：批量查询专业信息
                Map<String, CeeMajorDO> majorCache = batchQueryMajorInfo(filteredAdmissionList);
                log.info("为用户ID {}批量查询到{}个专业信息", userId, majorCache.size());

                // 检查任务是否被取消
                if (Thread.currentThread().isInterrupted()) {
                    log.info("用户ID {}的专业推荐任务在构建树形结构前被取消", userId);
                    return;
                }

                // 优化：直接使用已经过滤好的数据构建树形结构
                List<MajorAdmissionInfo> majorsWithEnrollmentPlan = filteredAdmissionList; // 已经包含招生计划信息
                log.info("为用户ID {}准备构建树形结构，共{}个专业", userId, majorsWithEnrollmentPlan.size());

                if (majorsWithEnrollmentPlan.isEmpty()) {
                    log.warn("用户ID {}经过招生计划过滤后无符合条件的专业", userId);
                    saveNoRecommendationResult(userId);
                    return;
                }

                // 检查任务是否被取消
                if (Thread.currentThread().isInterrupted()) {
                    log.info("用户ID {}的专业推荐任务在构建树形结构前被取消", userId);
                    return;
                }

                // 优化4：构建专业树形结构
                Map<String, Map<String, List<MajorInfo>>> groupedMajors = buildMajorTree(majorsWithEnrollmentPlan, majorCache);
                log.info("为用户ID {}构建了{}个学科门类的专业树", userId, groupedMajors.size());

                if (groupedMajors.isEmpty()) {
                    log.warn("用户ID {}未找到匹配的专业信息", userId);
                    saveNoRecommendationResult(userId);
                    return;
                }

                // 检查任务是否被取消
                if (Thread.currentThread().isInterrupted()) {
                    log.info("用户ID {}的专业推荐任务在保存结果前被取消", userId);
                    return;
                }

                // 优化5：保存推荐结果
                saveRecommendationResult(userId, groupedMajors);

                long endTime = System.currentTimeMillis();
                log.info("用户ID {}的专业推荐任务完成，耗时{}ms", userId, endTime - startTime);

            } catch (Exception e) {
                log.error("用户ID {}的专业推荐任务执行失败", userId, e);
            } finally {
                // 清理任务映射
                MAJOR_RECOMMENDATION_TASKS.remove(userId);
            }
        });

        // 保存任务映射
        MAJOR_RECOMMENDATION_TASKS.put(userId, task);

        // 记录线程池状态
        logThreadPoolStatus();
        log.info("为用户ID {}启动异步专业推荐任务", userId);
    }

    private void updateUserPost(UserSaveReqVO reqVO, AdminUserDO updateObj) {
        Long userId = reqVO.getId();
        Set<Long> dbPostIds = convertSet(userPostMapper.selectListByUserId(userId), UserPostDO::getPostId);
        // 计算新增和删除的岗位编号
        Set<Long> postIds = CollUtil.emptyIfNull(updateObj.getPostIds());
        Collection<Long> createPostIds = CollUtil.subtract(postIds, dbPostIds);
        Collection<Long> deletePostIds = CollUtil.subtract(dbPostIds, postIds);
        // 执行新增和删除。对于已经授权的岗位，不用做任何处理
        if (!CollectionUtil.isEmpty(createPostIds)) {
            userPostMapper.insertBatch(convertList(createPostIds,
                    postId -> new UserPostDO().setUserId(userId).setPostId(postId)));
        }
        if (!CollectionUtil.isEmpty(deletePostIds)) {
            userPostMapper.deleteByUserIdAndPostId(userId, deletePostIds);
        }
    }

    @Override
    public void updateUserLogin(Long id, String loginIp) {
        userMapper.updateById(new AdminUserDO().setId(id).setLoginIp(loginIp).setLoginDate(LocalDateTime.now()));
    }

    @Override
    public void updateUserProfile(Long id, UserProfileUpdateReqVO reqVO) {
        // 校验正确性
        validateUserExists(id);
        validateEmailUnique(id, reqVO.getEmail());
        validateMobileUnique(id, reqVO.getMobile());
        // 执行更新
        userMapper.updateById(BeanUtils.toBean(reqVO, AdminUserDO.class).setId(id));
    }

    @Override
    public void updateUserPassword(Long id, UserProfileUpdatePasswordReqVO reqVO) {
        // 校验旧密码密码
        validateOldPassword(id, reqVO.getOldPassword());
        // 执行更新
        AdminUserDO updateObj = new AdminUserDO().setId(id);
        updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码
        userMapper.updateById(updateObj);
    }

    @Override
    public String updateUserAvatar(Long id, InputStream avatarFile) {
        validateUserExists(id);
        // 存储文件
        String avatar = fileApi.createFile(IoUtil.readBytes(avatarFile));
        // 更新路径
        AdminUserDO sysUserDO = new AdminUserDO();
        sysUserDO.setId(id);
        sysUserDO.setAvatar(avatar);
        userMapper.updateById(sysUserDO);
        return avatar;
    }

    @Override
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_UPDATE_PASSWORD_SUB_TYPE, bizNo = "{{#id}}",
            success = SYSTEM_USER_UPDATE_PASSWORD_SUCCESS)
    public void updateUserPassword(Long id, String password) {
        // 1. 校验用户存在
        AdminUserDO user = validateUserExists(id);

        // 2. 更新密码
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setId(id);
        updateObj.setPassword(encodePassword(password)); // 加密密码
        userMapper.updateById(updateObj);

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("user", user);
        LogRecordContext.putVariable("newPassword", updateObj.getPassword());
    }

    @Override
    public void updateUserStatus(Long id, Integer status) {
        // 校验用户存在
        validateUserExists(id);
        // 更新状态
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setId(id);
        updateObj.setStatus(status);
        userMapper.updateById(updateObj);
    }

    @Override
    public void updateUserMobile(Long id, String mobile) {
        // 校验用户存在
        validateUserExists(id);
        // 校验手机号唯一性
        validateMobileUnique(id, mobile);
        // 更新手机号
        AdminUserDO updateObj = new AdminUserDO();
        updateObj.setId(id);
        updateObj.setMobile(mobile);
        userMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_DELETE_SUB_TYPE, bizNo = "{{#id}}",
            success = SYSTEM_USER_DELETE_SUCCESS)
    public void deleteUser(Long id) {
        // 1. 校验用户存在
        AdminUserDO user = validateUserExists(id);

        // 2.1 删除用户
        userMapper.deleteById(id);
        // 2.2 删除用户关联数据
        permissionService.processUserDeleted(id);
        // 2.2 删除用户岗位
        userPostMapper.deleteByUserId(id);

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("user", user);
    }

    @Override
    public AdminUserDO getUserByUsername(String username) {
        return userMapper.selectByUsername(username);
    }

    @Override
    public AdminUserDO getUserByMobile(String mobile) {
        return userMapper.selectByMobile(mobile);
    }

    @Override
    public PageResult<AdminUserDO> getUserPage(UserPageReqVO reqVO) {
        // 如果有角色编号，查询角色对应的用户编号
        Set<Long> userIds = reqVO.getRoleId() != null ?
                permissionService.getUserRoleIdListByRoleId(singleton(reqVO.getRoleId())) : null;

        // 分页查询
        return userMapper.selectPage(reqVO, getDeptCondition(reqVO.getDeptId()), userIds);
    }

    @Override
    public AdminUserDO getUser(Long id) {
        return userMapper.selectById(id);
    }

    @Override
    public List<AdminUserDO> getUserListByDeptIds(Collection<Long> deptIds) {
        if (CollUtil.isEmpty(deptIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectListByDeptIds(deptIds);
    }

    @Override
    public List<AdminUserDO> getUserListByPostIds(Collection<Long> postIds) {
        if (CollUtil.isEmpty(postIds)) {
            return Collections.emptyList();
        }
        Set<Long> userIds = convertSet(userPostMapper.selectListByPostIds(postIds), UserPostDO::getUserId);
        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyList();
        }
        return userMapper.selectBatchIds(userIds);
    }

    @Override
    public List<AdminUserDO> getUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return userMapper.selectBatchIds(ids);
    }

    @Override
    public void validateUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        // 获得岗位信息
        List<AdminUserDO> users = userMapper.selectBatchIds(ids);
        Map<Long, AdminUserDO> userMap = CollectionUtils.convertMap(users, AdminUserDO::getId);
        // 校验
        ids.forEach(id -> {
            AdminUserDO user = userMap.get(id);
            if (user == null) {
                throw exception(USER_NOT_EXISTS);
            }
            if (!CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus())) {
                throw exception(USER_IS_DISABLE, user.getNickname());
            }
        });
    }

    @Override
    public List<AdminUserDO> getUserListByNickname(String nickname) {
        return userMapper.selectListByNickname(nickname);
    }

    /**
     * 获得部门条件：查询指定部门的子部门编号们，包括自身
     *
     * @param deptId 部门编号
     * @return 部门编号集合
     */
    private Set<Long> getDeptCondition(Long deptId) {
        if (deptId == null) {
            return Collections.emptySet();
        }
        Set<Long> deptIds = convertSet(deptService.getChildDeptList(deptId), DeptDO::getId);
        deptIds.add(deptId); // 包括自身
        return deptIds;
    }

    private AdminUserDO validateUserForCreateOrUpdate(Long id, String username, String mobile, String email,
                                                      Long deptId, Set<Long> postIds) {
        // 关闭数据权限，避免因为没有数据权限，查询不到数据，进而导致唯一校验不正确
        return DataPermissionUtils.executeIgnore(() -> {
            // 校验用户存在
            AdminUserDO user = validateUserExists(id);
            // 校验用户名唯一
            validateUsernameUnique(id, username);
            // 校验手机号唯一
            validateMobileUnique(id, mobile);
            // 校验邮箱唯一
            validateEmailUnique(id, email);
            // 校验部门处于开启状态
            deptService.validateDeptList(CollectionUtils.singleton(deptId));
            // 校验岗位处于开启状态
            postService.validatePostList(postIds);
            return user;
        });
    }

    @VisibleForTesting
    AdminUserDO validateUserExists(Long id) {
        if (id == null) {
            return null;
        }
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }
        return user;
    }

    @VisibleForTesting
    void validateUsernameUnique(Long id, String username) {
        if (StrUtil.isBlank(username)) {
            return;
        }
        AdminUserDO user = userMapper.selectByUsername(username);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_USERNAME_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_USERNAME_EXISTS);
        }
    }

    @VisibleForTesting
    void validateEmailUnique(Long id, String email) {
        if (StrUtil.isBlank(email)) {
            return;
        }
        AdminUserDO user = userMapper.selectByEmail(email);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_EMAIL_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_EMAIL_EXISTS);
        }
    }

    @VisibleForTesting
    void validateMobileUnique(Long id, String mobile) {
        if (StrUtil.isBlank(mobile)) {
            return;
        }
        AdminUserDO user = userMapper.selectByMobile(mobile);
        if (user == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的用户
        if (id == null) {
            throw exception(USER_MOBILE_EXISTS);
        }
        if (!user.getId().equals(id)) {
            throw exception(USER_MOBILE_EXISTS);
        }
    }

    /**
     * 检查是否需要刷新专业推荐
     * 检查分数、最高分、最低分、省份、选科是否发生变化
     *
     * @param updateReqVO 更新请求VO
     * @param oldUser     原用户信息
     * @return 是否需要刷新推荐
     */
    @VisibleForTesting
    boolean checkIfNeedRefreshRecommendations(UserSaveReqVO updateReqVO, AdminUserDO oldUser) {
        // 检查分数是否发生变化
        boolean scoreChanged = isFieldChanged(updateReqVO.getScore(), oldUser.getScore());
        if (scoreChanged) {
            log.info("User ID {} score changed from {} to {}", updateReqVO.getId(), oldUser.getScore(), updateReqVO.getScore());
        }

        // 检查最低分数是否发生变化
        boolean minScoreChanged = isFieldChanged(updateReqVO.getMinScore(), oldUser.getMinScore());
        if (minScoreChanged) {
            log.info("User ID {} minScore changed from {} to {}", updateReqVO.getId(), oldUser.getMinScore(), updateReqVO.getMinScore());
        }

        // 检查最高分数是否发生变化
        boolean maxScoreChanged = isFieldChanged(updateReqVO.getMaxScore(), oldUser.getMaxScore());
        if (maxScoreChanged) {
            log.info("User ID {} maxScore changed from {} to {}", updateReqVO.getId(), oldUser.getMaxScore(), updateReqVO.getMaxScore());
        }

        // 检查省份是否发生变化
        boolean provinceChanged = isFieldChanged(updateReqVO.getProvince(), oldUser.getProvince());
        if (provinceChanged) {
            log.info("User ID {} province changed from {} to {}", updateReqVO.getId(), oldUser.getProvince(), updateReqVO.getProvince());
        }

        // 检查首选科目是否发生变化
        boolean firstSubjectChanged = isFieldChanged(updateReqVO.getFirstSubject(), oldUser.getFirstSubject());
        if (firstSubjectChanged) {
            log.info("User ID {} firstSubject changed from {} to {}", updateReqVO.getId(), oldUser.getFirstSubject(), updateReqVO.getFirstSubject());
        }

        // 检查次选科目是否发生变化
        boolean secondSubjectChanged = isFieldChanged(updateReqVO.getSecondSubject(), oldUser.getSecondSubject());
        if (secondSubjectChanged) {
            log.info("User ID {} secondSubject changed from {} to {}", updateReqVO.getId(), oldUser.getSecondSubject(), updateReqVO.getSecondSubject());
        }

        // 任何一个关键字段发生变化都需要刷新推荐
        return scoreChanged || minScoreChanged || maxScoreChanged || provinceChanged || firstSubjectChanged || secondSubjectChanged;
    }

    /**
     * 检查字段是否发生变化
     *
     * @param newValue 新值
     * @param oldValue 旧值
     * @return 是否发生变化
     */
    @VisibleForTesting
    boolean isFieldChanged(Object newValue, Object oldValue) {
        if (newValue == null && oldValue == null) {
            return false;
        }
        if (newValue == null || oldValue == null) {
            return true;
        }
        return !newValue.equals(oldValue);
    }

    /**
     * 校验分数区间
     *
     * @param reqVO 用户保存请求VO
     */
    @VisibleForTesting
    void validateScoreRange(UserSaveReqVO reqVO) {
        if (reqVO.getScore() == null) {
            return; // 如果用户分数为空，不进行分数区间校验
        }

        Double userScore = reqVO.getScore();
        Double minScore = reqVO.getMinScore();
        Double maxScore = reqVO.getMaxScore();

        // 校验最低分数
        if (minScore != null) {
            double minAllowed = Math.max(0, userScore - 100); // 不能低于用户分数减100分且不能低于0分
            if (minScore < minAllowed) {
                throw exception(new ErrorCode(400, "最低分数不能低于" + minAllowed + "分"));
            }
        }

        // 校验最高分数
        if (maxScore != null) {
            double maxAllowed = Math.min(750, userScore + 100); // 不能高于用户分数加100分且不能高于750分
            if (maxScore > maxAllowed) {
                throw exception(new ErrorCode(400, "最高分数不能高于" + maxAllowed + "分"));
            }
        }

        // 校验最低分数不能高于最高分数
        if (minScore != null && maxScore != null && minScore > maxScore) {
            throw exception(new ErrorCode(400, "最低分数不能高于最高分数"));
        }
    }

    /**
     * 校验旧密码
     *
     * @param id          用户 id
     * @param oldPassword 旧密码
     */
    @VisibleForTesting
    void validateOldPassword(Long id, String oldPassword) {
        AdminUserDO user = userMapper.selectById(id);
        if (user == null) {
            throw exception(USER_NOT_EXISTS);
        }
        if (!isPasswordMatch(oldPassword, user.getPassword())) {
            throw exception(USER_PASSWORD_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 添加事务，异常则回滚所有导入
    public UserImportRespVO importUserList(List<UserImportExcelVO> importUsers, boolean isUpdateSupport) {
        // 1.1 参数校验
        if (CollUtil.isEmpty(importUsers)) {
            throw exception(USER_IMPORT_LIST_IS_EMPTY);
        }
        // 1.2 初始化密码不能为空
        String initPassword = configApi.getConfigValueByKey(USER_INIT_PASSWORD_KEY);
        if (StrUtil.isEmpty(initPassword)) {
            throw exception(USER_IMPORT_INIT_PASSWORD);
        }

        // 2. 遍历，逐个创建 or 更新
        UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>())
                .updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
        importUsers.forEach(importUser -> {
            // 2.1.1 校验字段是否符合要求
            try {
                ValidationUtils.validate(BeanUtils.toBean(importUser, UserSaveReqVO.class).setPassword(initPassword));
            } catch (ConstraintViolationException ex) {
                respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
                return;
            }
            // 2.1.2 校验，判断是否有不符合的原因
            try {
                validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(),
                        importUser.getDeptId(), null);
            } catch (ServiceException ex) {
                respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
                return;
            }

            // 2.2.1 判断如果不存在，在进行插入
            AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername());
            if (existUser == null) {
                userMapper.insert(BeanUtils.toBean(importUser, AdminUserDO.class)
                        .setPassword(encodePassword(initPassword)).setPostIds(new HashSet<>())); // 设置默认密码及空岗位编号数组
                respVO.getCreateUsernames().add(importUser.getUsername());
                return;
            }
            // 2.2.2 如果存在，判断是否允许更新
            if (!isUpdateSupport) {
                respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMsg());
                return;
            }
            AdminUserDO updateUser = BeanUtils.toBean(importUser, AdminUserDO.class);
            updateUser.setId(existUser.getId());
            userMapper.updateById(updateUser);
            respVO.getUpdateUsernames().add(importUser.getUsername());
        });
        return respVO;
    }

    @Override
    public List<AdminUserDO> getUserListByStatus(Integer status) {
        return userMapper.selectListByStatus(status);
    }

    @Override
    public boolean isPasswordMatch(String rawPassword, String encodedPassword) {
        return passwordEncoder.matches(rawPassword, encodedPassword);
    }


    /**
     * 对密码进行加密
     *
     * @param password 密码
     * @return 加密后的密码
     */
    private String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }

    /**
     * 解析选科要求字符串，例如“首选物理，再选化学”
     *
     * @param subjectSelection 选科要求字符串
     * @return 选科要求集合
     */
    private Set<String> parseSubjectSelection(String subjectSelection) {
        Set<String> subjects = new HashSet<>();
        if (subjectSelection == null || subjectSelection.isEmpty()) {
            return subjects;
        }

        // 处理首选科目
        if (subjectSelection.contains("首选")) {
            int firstStart = subjectSelection.indexOf("首选") + 2; // “首选”长度为2
            int firstEnd = subjectSelection.indexOf("，", firstStart); // 逗号分隔首选和再选
            if (firstEnd == -1) {
                // 如果没有逗号，可能只有首选科目
                firstEnd = subjectSelection.length();
            }
            String firstSubject = subjectSelection.substring(firstStart, firstEnd).trim();
            subjects.add(firstSubject);
        }

        // 处理再选科目
        if (subjectSelection.contains("再选")) {
            int secondStart = subjectSelection.indexOf("再选") + 2; // “再选”长度为2
            String secondPart = subjectSelection.substring(secondStart).trim();
            // 再选科目可能有多个，用逗号分隔
            String[] secondSubjects = secondPart.split(",");
            for (String subject : secondSubjects) {
                subjects.add(subject.trim());
            }
        }

        return subjects;
    }

    /**
     * 检查用户选科是否符合专业的选科要求
     * @param userSubjects 用户选科集合
     * @param courseSelectionRequirements 专业选科要求字符串
     * @return 是否符合要求
     */
    private boolean checkSubjectRequirements(Set<String> userSubjects, String courseSelectionRequirements) {
        if (courseSelectionRequirements == null || courseSelectionRequirements.trim().isEmpty()) {
            return true; // 没有选科要求，默认符合
        }

        String requirements = courseSelectionRequirements.trim();

        // 不限选科
        if (requirements.equals("不限")) {
            return true;
        }

        // 标准化用户选科名称
        Set<String> normalizedUserSubjects = normalizeSubjectNames(userSubjects);

        log.debug("检查选科要求: {} vs 用户选科: {}", requirements, normalizedUserSubjects);

        // 处理各种选科要求格式
        if (requirements.contains("必选")) {
            return checkMustSelectRequirements(normalizedUserSubjects, requirements);
        } else if (requirements.contains("选1") || requirements.contains("2选1")) {
            return checkSelectOneRequirements(normalizedUserSubjects, requirements);
        } else if (requirements.contains("科必选")) {
            return checkMultipleMustSelectRequirements(normalizedUserSubjects, requirements);
        } else {
            // 默认处理：解析为必选科目
            return checkDefaultRequirements(normalizedUserSubjects, requirements);
        }
    }

    /**
     * 标准化选科名称
     */
    private Set<String> normalizeSubjectNames(Set<String> subjects) {
        Set<String> normalized = new HashSet<>();
        for (String subject : subjects) {
            String normalizedSubject = normalizeSubjectName(subject);
            if (normalizedSubject != null) {
                normalized.add(normalizedSubject);
            }
        }
        return normalized;
    }

    /**
     * 标准化单个选科名称
     */
    private String normalizeSubjectName(String subject) {
        if (subject == null) return null;

        String cleaned = subject.trim();

        // 标准化映射
        if (cleaned.contains("物理")) return "物理";
        if (cleaned.contains("化学")) return "化学";
        if (cleaned.contains("生物")) return "生物";
        if (cleaned.contains("历史")) return "历史";
        if (cleaned.contains("地理")) return "地理";
        if (cleaned.contains("政治") || cleaned.contains("思想政治")) return "政治";

        return cleaned;
    }

    /**
     * 检查必选科目要求（如：物理必选、化学必选）
     */
    private boolean checkMustSelectRequirements(Set<String> userSubjects, String requirements) {
        if (requirements.contains("物理必选") && !userSubjects.contains("物理")) {
            return false;
        }
        if (requirements.contains("化学必选") && !userSubjects.contains("化学")) {
            return false;
        }
        if (requirements.contains("生物必选") && !userSubjects.contains("生物")) {
            return false;
        }
        if (requirements.contains("历史必选") && !userSubjects.contains("历史")) {
            return false;
        }
        if (requirements.contains("地理必选") && !userSubjects.contains("地理")) {
            return false;
        }
        if (requirements.contains("思想政治必选") && !userSubjects.contains("政治")) {
            return false;
        }
        return true;
    }

    /**
     * 检查选一科目要求（如：物理/化学(2选1)、物/化/生(3选1)）
     */
    private boolean checkSelectOneRequirements(Set<String> userSubjects, String requirements) {
        // 提取选科选项
        Set<String> options = new HashSet<>();

        if (requirements.contains("物理/化学(2选1)")) {
            options.add("物理");
            options.add("化学");
        } else if (requirements.contains("物/化/生(3选1)")) {
            options.add("物理");
            options.add("化学");
            options.add("生物");
        } else if (requirements.contains("物/化/地(3选1)")) {
            options.add("物理");
            options.add("化学");
            options.add("地理");
        } else if (requirements.contains("化学/生物(2选1)")) {
            options.add("化学");
            options.add("生物");
        } else if (requirements.contains("史/生/政(3选1)")) {
            options.add("历史");
            options.add("生物");
            options.add("政治");
        } else if (requirements.contains("物/史/地(3选1)")) {
            options.add("物理");
            options.add("历史");
            options.add("地理");
        } else if (requirements.contains("生/政/地(3选1)")) {
            options.add("生物");
            options.add("政治");
            options.add("地理");
        } else if (requirements.contains("历史/地理(2选1)")) {
            options.add("历史");
            options.add("地理");
        } else if (requirements.contains("物/生/地(3选1)")) {
            options.add("物理");
            options.add("生物");
            options.add("地理");
        } else if (requirements.contains("物理/历史(2选1)")) {
            options.add("物理");
            options.add("历史");
        } else if (requirements.contains("史/政/地(3选1)")) {
            options.add("历史");
            options.add("政治");
            options.add("地理");
        } else if (requirements.contains("物理/地理(2选1)")) {
            options.add("物理");
            options.add("地理");
        } else if (requirements.contains("物/政/地(3选1)")) {
            options.add("物理");
            options.add("政治");
            options.add("地理");
        } else if (requirements.contains("史/化/地(3选1)")) {
            options.add("历史");
            options.add("化学");
            options.add("地理");
        }

        // 检查用户是否选择了其中至少一科
        for (String option : options) {
            if (userSubjects.contains(option)) {
                return true;
            }
        }

        return options.isEmpty(); // 如果没有识别到选项，默认通过
    }

    /**
     * 检查多科必选要求（如：化学、生物(2科必选)、物理、化学(2科必选)）
     */
    private boolean checkMultipleMustSelectRequirements(Set<String> userSubjects, String requirements) {
        if (requirements.contains("化学、生物(2科必选)")) {
            return userSubjects.contains("化学") && userSubjects.contains("生物");
        } else if (requirements.contains("物理、化学(2科必选)")) {
            return userSubjects.contains("物理") && userSubjects.contains("化学");
        } else if (requirements.contains("历史、地理(2科必选)")) {
            return userSubjects.contains("历史") && userSubjects.contains("地理");
        } else if (requirements.contains("物、化、生(3科必选)")) {
            return userSubjects.contains("物理") && userSubjects.contains("化学") && userSubjects.contains("生物");
        } else if (requirements.contains("史、政、地(3科必选)")) {
            return userSubjects.contains("历史") && userSubjects.contains("政治") && userSubjects.contains("地理");
        } else if (requirements.contains("物理、生物(2科必选)")) {
            return userSubjects.contains("物理") && userSubjects.contains("生物");
        }

        return true; // 未识别的格式默认通过
    }

    /**
     * 检查默认选科要求
     */
    private boolean checkDefaultRequirements(Set<String> userSubjects, String requirements) {
        // 解析选科要求中的科目
        Set<String> requiredSubjects = parseSubjectSelection(requirements);

        // 检查用户是否选择了所有要求的科目
        for (String required : requiredSubjects) {
            String normalized = normalizeSubjectName(required);
            if (normalized != null && !userSubjects.contains(normalized)) {
                return false;
            }
        }

        return true;
    }

    /**
     * 将MajorAdmissionDO列表转换为MajorAdmissionInfo列表
     *
     * @param admissionDOList MajorAdmissionDO列表
     * @return MajorAdmissionInfo列表
     */
    private List<MajorAdmissionInfo> convertToMajorAdmissionInfoList(List<MajorAdmissionDO> admissionDOList) {
        if (admissionDOList == null || admissionDOList.isEmpty()) {
            return new ArrayList<>();
        }

        List<MajorAdmissionInfo> result = new ArrayList<>(admissionDOList.size());
        for (MajorAdmissionDO admissionDO : admissionDOList) {
            MajorAdmissionInfo info = new MajorAdmissionInfo();
            info.setProvinceName(admissionDO.getProvinceName());
            info.setSchoolUUID(admissionDO.getSchoolUuid());
            info.setSchoolName(admissionDO.getSchoolName());
            info.setMajorName(admissionDO.getMajorName());
            info.setMajorCode(admissionDO.getMajorCode());
            info.setYear(admissionDO.getYear());
            info.setHighScore(admissionDO.getHighScore());
            info.setAverageScore(admissionDO.getAverageScore());
            info.setLowestScore(admissionDO.getLowestScore());
            info.setLowestSection(admissionDO.getLowestSection());
            info.setBatchName(admissionDO.getBatchName());
            info.setTypeName(admissionDO.getTypeName());
            info.setProScore(admissionDO.getProScore());
            info.setSubjectSelection(admissionDO.getSubjectSelection());
            info.setSubjectGroup(admissionDO.getSubjectGroup());
            info.setMajorStandardCode(admissionDO.getMajorStandardCode());
            result.add(info);
        }

        return result;
    }

    /**
     * 同步获取用户排名信息
     *
     * @param user 用户对象
     */
    private void getUserRanking(AdminUserDO user) {
        if (user == null || user.getProvince() == null || user.getScore() == null) {
            log.warn("Cannot get ranking for user with null province or score");
            return;
        }

        final Long userId = user.getId();
        final String province = user.getProvince();
        final Double userScore = user.getScore();
        final String secondSubject = user.getSecondSubject();

        try {
            log.info("Starting synchronous ranking retrieval for user ID {}", userId);

            // 使用2024年的数据，因为2025年数据尚未更新
            String year = "2024";

            // 确定科目选择类型
            String subjectSelection = SubjectSelectionUtils.getSubjectSelectionType(province, year, secondSubject);

            // 将Double转换为String以便于查询
            String scoreStr = String.valueOf(userScore.intValue());

            // 从数据库查询分数段数据
            List<ScoreSegmentDO> scoreSegments = scoreSegmentService.getScoreSegmentListByCondition(
                    year, province, subjectSelection, user.getScore()+"", user.getScore()+"", null);

            if (scoreSegments.isEmpty()) {
                log.warn("No score segment data found for year: {}, province: {}, subjectSelection: {}",
                        year, province, subjectSelection);
                return;
            }

            // 查找匹配的分数段
            ScoreSegmentDO matchedSegment = findMatchingScoreSegment(scoreSegments, scoreStr);

            if (matchedSegment != null) {
                // 更新用户的排名信息
                AdminUserDO updateObj = new AdminUserDO();
                updateObj.setId(userId);
                updateObj.setRanking(matchedSegment.getRanking());
                updateObj.setRankingRange(matchedSegment.getRankingRange());
                userMapper.updateById(updateObj);

                // 同时更新成绩表中的排名信息
                try {
                    userScoresService.updateCurrentScoreRanking(userId, matchedSegment.getRanking(), matchedSegment.getRankingRange());
                } catch (Exception e) {
                    log.warn("Failed to update ranking in scores table for user ID {}: {}", userId, e.getMessage());
                }

                log.info("User ID {} updated with ranking: {}, rankingRange: {}",
                        userId, matchedSegment.getRanking(), matchedSegment.getRankingRange());
            } else {
                log.warn("No matching score segment found for user ID {} with score {}", userId, scoreStr);
            }
        } catch (Exception e) {
            log.error("Error while retrieving ranking information for user ID " + userId, e);
        }
    }

    /**
     * 异步获取用户排名信息
     *
     * @param user 用户对象
     */
    private void asyncGetUserRanking(AdminUserDO user) {
        if (user == null || user.getProvince() == null || user.getScore() == null) {
            log.warn("Cannot get ranking for user with null province or score");
            return;
        }

        final Long userId = user.getId();
        final String province = user.getProvince();
        final Double userScore = user.getScore();
        final String secondSubject = user.getSecondSubject();

        // 取消之前的任务（如果存在）
        Future<?> previousTask = RANKING_TASKS.get(userId);
        if (previousTask != null && !previousTask.isDone()) {
            log.info("Cancelling previous ranking task for user ID {}", userId);
            previousTask.cancel(true);
        }

        // 创建新的任务
        Future<?> task = RANKING_EXECUTOR.submit(() -> {
            try {
                // 检查任务是否被取消
                if (Thread.currentThread().isInterrupted()) {
                    log.info("Ranking task for user ID {} was cancelled before starting", userId);
                    return;
                }

                log.info("Starting async ranking retrieval for user ID {}", userId);

                // 使用2024年的数据，因为2025年数据尚未更新
                String year = "2024";

                // 确定科目选择类型
                String subjectSelection = SubjectSelectionUtils.getSubjectSelectionType(province, year, secondSubject);

                // 将Double转换为String以便于查询
                String scoreStr = String.valueOf(userScore.intValue());

                // 检查任务是否被取消
                if (Thread.currentThread().isInterrupted()) {
                    log.info("Ranking task for user ID {} was cancelled before database query", userId);
                    return;
                }

                // 从数据库查询分数段数据
                List<ScoreSegmentDO> scoreSegments = scoreSegmentService.getScoreSegmentListByCondition(
                        year, province, subjectSelection, user.getScore()+"", user.getScore()+"", null);

                if (scoreSegments.isEmpty()) {
                    log.warn("No score segment data found for year: {}, province: {}, subjectSelection: {}",
                            year, province, subjectSelection);
                    return;
                }

                // 检查任务是否被取消
                if (Thread.currentThread().isInterrupted()) {
                    log.info("Ranking task for user ID {} was cancelled after database query", userId);
                    return;
                }

                // 查找匹配的分数段
                ScoreSegmentDO matchedSegment = findMatchingScoreSegment(scoreSegments, scoreStr);

                if (matchedSegment != null) {
                    // 检查任务是否被取消
                    if (Thread.currentThread().isInterrupted()) {
                        log.info("Ranking task for user ID {} was cancelled before database update", userId);
                        return;
                    }

                    // 更新用户的排名信息
                    AdminUserDO updateObj = new AdminUserDO();
                    updateObj.setId(userId);
                    updateObj.setRanking(matchedSegment.getRanking());
                    updateObj.setRankingRange(matchedSegment.getRankingRange());
                    userMapper.updateById(updateObj);

                    // 同时更新成绩表中的排名信息
                    try {
                        userScoresService.updateCurrentScoreRanking(userId, matchedSegment.getRanking(), matchedSegment.getRankingRange());
                    } catch (Exception e) {
                        log.warn("Failed to update ranking in scores table for user ID {}: {}", userId, e.getMessage());
                    }

                    log.info("User ID {} updated with ranking: {}, rankingRange: {}",
                            userId, matchedSegment.getRanking(), matchedSegment.getRankingRange());

                    // 任务完成，从映射中移除
                    RANKING_TASKS.remove(userId);
                } else {
                    log.warn("No matching score segment found for user ID {} with score {}", userId, scoreStr);

                    // 检查任务是否被取消
                    if (Thread.currentThread().isInterrupted()) {
                        log.info("Ranking task for user ID {} was cancelled before updating with -1", userId);
                        return;
                    }

                    // 没有找到匹配的分数段，更新排名为-1
                    AdminUserDO updateObj = new AdminUserDO();
                    updateObj.setId(userId);
                    updateObj.setRanking("-1");
                    updateObj.setRankingRange("-1");
                    userMapper.updateById(updateObj);

                    // 同时更新成绩表中的排名信息
                    try {
                        userScoresService.updateCurrentScoreRanking(userId, "-1", "-1");
                    } catch (Exception e) {
                        log.warn("Failed to update ranking in scores table for user ID {}: {}", userId, e.getMessage());
                    }

                    log.info("User ID {} updated with ranking: -1, rankingRange: -1 (no matching score segment)", userId);

                    // 任务完成，从映射中移除
                    RANKING_TASKS.remove(userId);
                }
            } catch (Exception e) {
                if (e instanceof InterruptedException || Thread.currentThread().isInterrupted()) {
                    log.info("Ranking task for user ID {} was interrupted", userId);
                } else {
                    log.error("Error while retrieving ranking information for user ID " + userId, e);
                }
            }
        });

        // 将任务添加到映射中
        RANKING_TASKS.put(userId, task);
        log.info("Started async ranking retrieval process for user ID {}", userId);
    }

    /**
     * 同步更新用户成绩表
     *
     * @param user 用户对象
     */
    private void syncUserScores(AdminUserDO user) {
        if (user == null || user.getId() == null) {
            log.warn("Cannot sync scores for null user or user with null ID");
            return;
        }

        try {
            // 检查用户是否有成绩相关字段
            if (user.getProvince() == null && user.getGrade() == null &&
                user.getFirstSubject() == null && user.getSecondSubject() == null &&
                user.getScore() == null && user.getRanking() == null &&
                user.getRankingRange() == null && user.getTypeName() == null &&
                user.getMinScore() == null && user.getMaxScore() == null) {
                log.info("User ID {} has no score-related fields to sync", user.getId());
                return;
            }

            // 创建新的成绩记录
            UserScoresSaveReqVO createReqVO = new UserScoresSaveReqVO();
            createReqVO.setUserId(user.getId());
            createReqVO.setProvince(user.getProvince());
            createReqVO.setGrade(user.getGrade());
            createReqVO.setFirstSubject(user.getFirstSubject());
            createReqVO.setSecondSubject(user.getSecondSubject());
            createReqVO.setScore(user.getScore() != null ? BigDecimal.valueOf(user.getScore()) : null);
            createReqVO.setRanking(user.getRanking());
            createReqVO.setRankingRange(user.getRankingRange());
            createReqVO.setTypeName(user.getTypeName());
            createReqVO.setMinScore(user.getMinScore() != null ? BigDecimal.valueOf(user.getMinScore()) : null);
            createReqVO.setMaxScore(user.getMaxScore() != null ? BigDecimal.valueOf(user.getMaxScore()) : null);
            createReqVO.setExamYear(LocalDateTime.now().getYear());
            createReqVO.setIsCurrent(true);
            createReqVO.setRemark("系统同步更新");
            
            userScoresService.createUserScore(createReqVO);

            log.info("Successfully synced scores for user ID {}", user.getId());
        } catch (Exception e) {
            log.error("Error while syncing scores for user ID " + user.getId(), e);
        }
    }

    /**
     * 根据省份和首选科目确定科目选择类型
     *
     * @param province     省份
     * @param firstSubject 首选科目
     * @return 科目选择类型
     */
    private String determineSubjectSelection(String province, String firstSubject) {
        // 获取当前年份
        String year = String.valueOf(java.time.Year.now().getValue());

        // 使用SubjectSelectionUtils工具类获取科目选择类型
        return SubjectSelectionUtils.getSubjectSelectionType(province, year, firstSubject);
    }

    /**
     * 根据专业录取信息确定教育级别
     * 优先通过批次名称判断，失败后再通过 majorStandardCode 查询 CeeMajor 表
     *
     * @param info 专业录取信息
     * @return 教育级别（本科/专科）
     */
    private String determineEducationLevel(MajorAdmissionInfo info) {
        if (info == null) {
            return "本科"; // 默认为本科
        }

        // 第一优先级：通过批次名称判断教育级别
        String educationLevelFromBatch = determineEducationLevelByBatchName(info.getBatchName());
        if (educationLevelFromBatch != null) {
            return educationLevelFromBatch;
        }

        // 第二优先级：如果批次名称无法判断，通过 majorStandardCode 查询 CeeMajor 表
        if (info.getMajorStandardCode() != null && !info.getMajorStandardCode().isEmpty()) {
            try {
                // 处理 majorStandardCode 与 majorCode 的差异
                // 例如：570102K -> 570102，去除末尾的字母
                String majorCode = normalizeMajorCode(info.getMajorStandardCode());

                // 根据专业代码查询专业信息
                CeeMajorDO major = ceeMajorService.getMajorByCode(majorCode);

                if (major != null && major.getEducationLevel() != null) {
                    return major.getEducationLevel();
                }

                // 如果没有找到专业信息，尝试使用原始的 majorStandardCode
                if (!majorCode.equals(info.getMajorStandardCode())) {
                    major = ceeMajorService.getMajorByCode(info.getMajorStandardCode());
                    if (major != null && major.getEducationLevel() != null) {
                        return major.getEducationLevel();
                    }
                }

            } catch (Exception e) {
                log.warn("根据专业代码查询教育级别失败: {}, 错误: {}", info.getMajorStandardCode(), e.getMessage());
            }
        }

        // 如果两种方法都无法确定教育级别，默认返回本科
        log.debug("无法通过批次名称和专业代码确定教育级别，批次: {}, 专业代码: {}, 默认返回本科",
                 info.getBatchName(), info.getMajorStandardCode());
        return "本科";
    }

    /**
     * 标准化专业代码，处理 majorStandardCode 与 majorCode 的差异
     * 例如：570102K -> 570102
     *
     * @param majorStandardCode 专业标准代码
     * @return 标准化后的专业代码
     */
    private String normalizeMajorCode(String majorStandardCode) {
        if (majorStandardCode == null || majorStandardCode.isEmpty()) {
            return majorStandardCode;
        }

        // 去除末尾的字母（如 K、T 等）
        return majorStandardCode.replaceAll("[A-Za-z]+$", "");
    }

    /**
     * 根据批次名称确定教育级别
     *
     * @param batchName 批次名称
     * @return 教育级别（本科/专科），如果无法判断则返回 null
     */
    private String determineEducationLevelByBatchName(String batchName) {
        if (batchName == null || batchName.isEmpty()) {
            return null; // 无法判断
        }

        // 转换为小写进行匹配，提高匹配准确性
        String lowerBatchName = batchName.toLowerCase();

        // 第一优先级：直接检查是否包含"专科"或"本科"字眼
        if (lowerBatchName.contains("专科")) {
            return "专科";
        }

        if (lowerBatchName.contains("本科")) {
            return "本科";
        }

        // 第二优先级：如果没有明确的"专科"或"本科"字眼，则通过其他关键词判断

        // 判断专科相关关键词
        if (lowerBatchName.contains("高职")) {
            return "专科";
        }

        // 判断本科相关关键词
        if (lowerBatchName.contains("一批") ||
            lowerBatchName.contains("二批") ||
            lowerBatchName.contains("三批") ||
            lowerBatchName.contains("第一批") ||
            lowerBatchName.contains("第二批") ||
            lowerBatchName.contains("国家专项") ||
            lowerBatchName.contains("高校专项") ||
            lowerBatchName.contains("地方专项") ||
            lowerBatchName.contains("区域专项") ||
            lowerBatchName.contains("特殊类型") ||
            lowerBatchName.contains("提前批") ||
            lowerBatchName.contains("零批次") ||
            lowerBatchName.contains("零志愿") ||
            lowerBatchName.contains("平行录取") ||
            lowerBatchName.contains("普通类") ||
            lowerBatchName.contains("一段") ||
            lowerBatchName.contains("二段") ||
            lowerBatchName.contains("三段") ||
            lowerBatchName.contains("预科") ||
            lowerBatchName.contains("免费定向") ||
            lowerBatchName.contains("少数民族") ||
            lowerBatchName.contains("一类模式") ||
            lowerBatchName.contains("分类招生")) {
            return "本科";
        }

        // 对于无法明确判断的批次，返回 null，让上层方法继续尝试其他判断方式
        log.debug("批次名称无法判断教育级别: {}", batchName);
        return null;
    }

    /**
     * 在分数段列表中查找匹配的分数段
     *
     * @param scoreSegments 分数段列表
     * @param userScore     用户分数
     * @return 匹配的分数段
     */
    private ScoreSegmentDO findMatchingScoreSegment(List<ScoreSegmentDO> scoreSegments, String userScore) {
        for (ScoreSegmentDO segment : scoreSegments) {
            String examScore = segment.getExaminationScore();

            // 如果是精确匹配
            if (examScore.equals(userScore)) {
                return segment;
            }

            // 如果是区间匹配（例如 "673-750"）
            if (examScore.contains("-")) {
                String[] range = examScore.split("-");
                if (range.length == 2) {
                    try {
                        int min = Integer.parseInt(range[0]);
                        int max = Integer.parseInt(range[1]);
                        int score = Integer.parseInt(userScore);

                        if (score >= min && score <= max) {
                            return segment;
                        }
                    } catch (NumberFormatException e) {
                        // 忽略解析错误，继续检查下一个分数段
                    }
                }
            }
        }
        return null;
    }

    /**
     * 根据openId获取用户 (兼容性保留)
     *
     * @param openId
     * @return
     */
    @Override
    public AdminUserDO getUserByOpenId(String openId) {
        QueryWrapper<AdminUserDO> wrapper = new QueryWrapper<>();
        wrapper.and(w -> w.eq("open_id", openId)
                .or().eq("wechat_open_id", openId)
                .or().eq("kuaishou_open_id", openId));
        wrapper.last("LIMIT 1"); // 确保只返回一条记录
        return userMapper.selectOne(wrapper);
    }

    @Override
    public AdminUserDO getUserByWechatOpenId(String wechatOpenId) {
        return userMapper.selectByWechatOpenId(wechatOpenId);
    }

    @Override
    public AdminUserDO getUserByKuaishouOpenId(String kuaishouOpenId) {
        return userMapper.selectByKuaishouOpenId(kuaishouOpenId);
    }

    /**
     * 在应用程序关闭时优雅地关闭线程池
     */
    @PreDestroy
    public void shutdown() {
        log.info("开始关闭线程池...");

        // 关闭排名查询线程池
        log.info("关闭排名查询线程池...");
        for (Map.Entry<Long, Future<?>> entry : RANKING_TASKS.entrySet()) {
            Long userId = entry.getKey();
            Future<?> task = entry.getValue();
            if (!task.isDone()) {
                log.info("取消用户ID {}的排名查询任务", userId);
                task.cancel(true);
            }
        }
        RANKING_TASKS.clear();

        RANKING_EXECUTOR.shutdown();
        try {
            if (!RANKING_EXECUTOR.awaitTermination(5, TimeUnit.SECONDS)) {
                log.warn("排名查询线程池未在指定时间内关闭");
                RANKING_EXECUTOR.shutdownNow();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            RANKING_EXECUTOR.shutdownNow();
            log.error("排名查询线程池关闭被中断", e);
        }
        log.info("排名查询线程池已关闭");

        // 关闭专业推荐线程池
        log.info("关闭专业推荐线程池...");
        for (Map.Entry<Long, Future<?>> entry : MAJOR_RECOMMENDATION_TASKS.entrySet()) {
            Long userId = entry.getKey();
            Future<?> task = entry.getValue();
            if (!task.isDone()) {
                log.info("取消用户ID {}的专业推荐任务", userId);
                task.cancel(true);
            }
        }
        MAJOR_RECOMMENDATION_TASKS.clear();

        MAJOR_RECOMMENDATION_EXECUTOR.shutdown();
        try {
            if (!MAJOR_RECOMMENDATION_EXECUTOR.awaitTermination(10, TimeUnit.SECONDS)) {
                log.warn("专业推荐线程池未在指定时间内关闭");
                MAJOR_RECOMMENDATION_EXECUTOR.shutdownNow();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            MAJOR_RECOMMENDATION_EXECUTOR.shutdownNow();
            log.error("专业推荐线程池关闭被中断", e);
        }
        log.info("专业推荐线程池已关闭");

        log.info("所有线程池已关闭");
    }

    /**
     * 检查用户是否有正在生成中的报告
     *
     * @param userId 用户ID
     * @return 如果有正在生成中的报告，返回true；否则返回false
     */
    private boolean hasGeneratingReport(Long userId) {
        if (userId == null) {
            return false;
        }

        // 查询用户是否有状态为2（生成报告中）的报告记录
        return answerRecordMapper.selectCount(new LambdaQueryWrapperX<AnswerRecordDO>()
                .eq(AnswerRecordDO::getUserId, userId.intValue()) // 将Long转为Integer
                .eq(AnswerRecordDO::getStatus, 1)) > 0;
    }

    // ==================== 优化后的辅助方法 ====================

    /**
     * 解析用户选科信息
     */
    private Set<String> parseUserSubjects(String secondSubject) {
        final Set<String> userSubjects = new HashSet<>();
        if (secondSubject != null && !secondSubject.isEmpty()) {
            String[] subjects = secondSubject.split(",");
            for (String subject : subjects) {
                userSubjects.add(subject.trim());
            }
        }
        return userSubjects;
    }

    /**
     * 批量过滤选科要求（使用新的选科检查逻辑）
     */
    private List<MajorAdmissionInfo> batchFilterBySubjects(List<MajorAdmissionInfo> admissionList, Set<String> userSubjects) {
        if (userSubjects.isEmpty()) {
            return admissionList; // 如果用户没有选科信息，不进行过滤
        }

        List<MajorAdmissionInfo> filteredBySubjects = new ArrayList<>();
        int filteredCount = 0;

        for (MajorAdmissionInfo info : admissionList) {
            boolean passesSubjectCheck = true;

            // 检查专业录取数据中的选科要求
            if (info.getSubjectSelection() != null && !info.getSubjectSelection().isEmpty()) {
                if (!checkSubjectRequirements(userSubjects, info.getSubjectSelection())) {
                    log.debug("专业 {} - {} 不符合选科要求: {}，用户选科: {}",
                            info.getSchoolName(), info.getMajorName(), info.getSubjectSelection(), userSubjects);
                    passesSubjectCheck = false;
                }
            }

            if (passesSubjectCheck) {
                filteredBySubjects.add(info);
            } else {
                filteredCount++;
            }
        }

        log.info("选科筛选完成 - 原始数量: {}，过滤掉: {}，保留: {}",
                admissionList.size(), filteredCount, filteredBySubjects.size());
        return filteredBySubjects;
    }

    /**
     * 批量查询专业信息
     */
    private Map<String, CeeMajorDO> batchQueryMajorInfo(List<MajorAdmissionInfo> filteredBySubjects) {
        // 收集所有需要查询的专业名称
        Map<String, String> originalToCleanedMajorNames = new HashMap<>();
        Map<String, String> majorToEducationLevel = new HashMap<>();

        for (MajorAdmissionInfo info : filteredBySubjects) {
            if (info.getMajorName() != null && !info.getMajorName().isEmpty()) {
                // 去除括号及其中的内容
                String majorName = info.getMajorName()
                        .replaceAll("\\([^)]*\\)", "")
                        .replaceAll("（[^）]*）", "")
                        .trim();

                if (!majorName.isEmpty()) {
                    originalToCleanedMajorNames.put(info.getMajorName(), majorName);
                    // 根据专业录取信息确定教育级别
                    String educationLevel = determineEducationLevel(info);
                    majorToEducationLevel.put(majorName, educationLevel);
                }
            }
        }

        Map<String, CeeMajorDO> majorCache = new HashMap<>();

        // 批量精确匹配查询
        Set<String> uniqueMajorNames = new HashSet<>(originalToCleanedMajorNames.values());
        for (String majorName : uniqueMajorNames) {
            String educationLevel = majorToEducationLevel.getOrDefault(majorName, "本科");
            CeeMajorDO major = ceeMajorService.getMajorByNameAndEducationLevel(majorName, educationLevel);
            if (major != null) {
                majorCache.put(majorName, major);
            }
        }

        // 对于未找到的专业，进行模糊查询（限制数量）
        Set<String> remainingMajors = new HashSet<>(uniqueMajorNames);
        remainingMajors.removeAll(majorCache.keySet());

        if (!remainingMajors.isEmpty()) {
            // 处理所有剩余的专业，不限制数量
            for (String majorName : remainingMajors) {
                String educationLevel = majorToEducationLevel.getOrDefault(majorName, "本科");
                List<CeeMajorDO> majors = ceeMajorService.searchMajorsByName(majorName, educationLevel);
                if (!majors.isEmpty()) {
                    majorCache.put(majorName, majors.get(0));
                } else {
                    // 如果还是没有找到，尝试不指定教育级别
                    majors = ceeMajorService.searchMajorsByName(majorName, null);
                    if (!majors.isEmpty()) {
                        majorCache.put(majorName, majors.get(0));
                    }
                }
            }
        }

        return majorCache;
    }

    /**
     * 构建专业树形结构
     */
    private Map<String, Map<String, List<MajorInfo>>> buildMajorTree(List<MajorAdmissionInfo> filteredBySubjects,
                                                                     Map<String, CeeMajorDO> majorCache) {
        Map<String, Map<String, List<MajorInfo>>> groupedMajors = new HashMap<>();

        // 创建专业名称映射
        Map<String, String> originalToCleanedMajorNames = new HashMap<>();
        for (MajorAdmissionInfo info : filteredBySubjects) {
            if (info.getMajorName() != null && !info.getMajorName().isEmpty()) {
                String majorName = info.getMajorName()
                        .replaceAll("\\([^)]*\\)", "")
                        .replaceAll("（[^）]*）", "")
                        .trim();
                if (!majorName.isEmpty()) {
                    originalToCleanedMajorNames.put(info.getMajorName(), majorName);
                }
            }
        }

        // 使用缓存的专业信息处理每个专业
        for (MajorAdmissionInfo info : filteredBySubjects) {
            if (info.getMajorName() != null && !info.getMajorName().isEmpty()) {
                String majorName = originalToCleanedMajorNames.get(info.getMajorName());

                if (majorName != null && !majorName.isEmpty()) {
                    CeeMajorDO major = majorCache.get(majorName);
                    if (major != null) {
                        String category = major.getDisciplinaryCategory();
                        String subCategory = major.getDisciplinarySubCategory();

                        // 确保学科门类存在
                        groupedMajors.putIfAbsent(category, new HashMap<>());

                        // 确保学科子类存在
                        Map<String, List<MajorInfo>> subCategoryMap = groupedMajors.get(category);
                        subCategoryMap.putIfAbsent(subCategory, new ArrayList<>());

                        // 创建专业信息对象
                        MajorInfo majorInfo = new MajorInfo();
                        majorInfo.setId(major.getId());
                        majorInfo.setName(major.getMajorName());
                        majorInfo.setCode(major.getMajorCode());
                        majorInfo.setEducationLevel(major.getEducationLevel());
                        majorInfo.setIsRecommended(major.getIsRecommended());
                        majorInfo.setCareerDirection(major.getCareerDirection());
                        majorInfo.setMajorIntroduction(major.getMajorIntroduction());
                        majorInfo.setGraduateScale(major.getGraduateScale());
                        majorInfo.setMaleFemaleRatio(major.getMaleFemaleRatio());
                        majorInfo.setRecommendSchools(major.getRecommendSchools());
                        majorInfo.setCourses(major.getCourses());

                        // 添加专业信息到对应的学科子类下
                        List<MajorInfo> majors = subCategoryMap.get(subCategory);
                        // 检查是否已存在相同ID的专业，避免重复
                        boolean exists = majors.stream().anyMatch(m -> m.getId().equals(majorInfo.getId()));
                        if (!exists) {
                            majors.add(majorInfo);
                        }
                    }
                }
            }
        }

        return groupedMajors;
    }

    /**
     * 批量过滤招生计划数据（数据库版本）
     * 只保留有招生计划且符合选科要求的专业
     */
    private List<MajorAdmissionInfo> batchFilterEnrollmentPlans(List<MajorAdmissionInfo> admissionList,
                                                               String province, String typeName, Set<String> userSubjects) {
        if (admissionList == null || admissionList.isEmpty()) {
            return new ArrayList<>();
        }

        long startTime = System.currentTimeMillis();
        PerformanceMonitor.PerformanceTimer timer = PerformanceMonitor.startTimer("batchFilterEnrollmentPlans");
        log.info("开始批量过滤招生计划（数据库版本），总数量: {}", admissionList.size());

        try {
            // 提取所有学校名称和专业名称
            List<String> schoolNames = admissionList.stream()
                    .map(MajorAdmissionInfo::getSchoolName)
                    .filter(Objects::nonNull)
                    .distinct()
                    .collect(Collectors.toList());

            List<String> majorNames = admissionList.stream()
                    .map(MajorAdmissionInfo::getMajorName)
                    .filter(Objects::nonNull)
                    .distinct()
                    .collect(Collectors.toList());

            log.info("提取到{}个不重复学校，{}个不重复专业", schoolNames.size(), majorNames.size());

            // 批量查询数据库中存在招生计划的学校专业组合（支持多年份查询）
            List<CollegeEnrollmentPlanDO> existingPlans = collegeEnrollmentPlanService
                    .batchCheckEnrollmentPlansMultiYear(schoolNames, majorNames, province);

            log.info("数据库中找到{}个有招生计划的学校专业组合", existingPlans.size());

            // 构建符合选科要求且有招生计划的学校专业组合集合
            Set<String> validCombinations = new HashSet<>();
            for (CollegeEnrollmentPlanDO plan : existingPlans) {
                // 检查选科要求
                if (userSubjects.isEmpty() || checkSubjectRequirements(userSubjects, plan.getCourseSelectionRequirements())) {
                    // 去除专业名称中的括号内容，确保与MajorAdmissionInfo中的majorName能够匹配
                    String cleanMajorName = removeBrackets(plan.getCollegeMajorName());
                    String combination = plan.getSchoolName() + ":" + cleanMajorName;
                    validCombinations.add(combination);
                }
            }

            log.info("符合选科要求的招生计划组合: {}", validCombinations.size());

            // 过滤出有招生计划且符合选科要求的专业
            List<MajorAdmissionInfo> filteredList = admissionList.stream()
                    .filter(admission -> {
                        // 去除专业名称中的括号内容，确保与招生计划数据能够匹配
                        String cleanMajorName = removeBrackets(admission.getMajorName());
                        String combination = admission.getSchoolName() + ":" + cleanMajorName;
                        return validCombinations.contains(combination);
                    })
                    .collect(Collectors.toList());

            long endTime = System.currentTimeMillis();
            log.info("批量过滤完成，原始数量: {}, 过滤后数量: {}, 耗时: {}ms",
                     admissionList.size(), filteredList.size(), endTime - startTime);

            timer.recordSuccess();
            return filteredList;

        } catch (Exception e) {
            log.error("批量过滤招生计划数据时发生异常", e);
            timer.recordFailure();
            return new ArrayList<>();
        } finally {
            // timer.recordSuccess() 已在正常流程中调用
        }
    }



    /**
     * 去除专业名称中的括号及其内容
     * @param majorName 专业名称
     * @return 清理后的专业名称
     */
    private String removeBrackets(String majorName) {
        if (majorName == null || majorName.trim().isEmpty()) {
            return majorName;
        }
        return majorName.replaceAll("\\([^)]*\\)", "").trim();
    }

    /**
     * 安全地将字符串转换为数值
     * 处理可能的格式问题，如区间分数、非数值字符等
     */
    private double parseScoreSafely(String scoreStr) {
        if (scoreStr == null || scoreStr.trim().isEmpty()) {
            return 0.0;
        }

        try {
            // 去除空格
            String cleanScore = scoreStr.trim();

            // 处理区间分数（如"600-650"），取平均值
            if (cleanScore.contains("-")) {
                String[] parts = cleanScore.split("-");
                if (parts.length == 2) {
                    double min = Double.parseDouble(parts[0].trim());
                    double max = Double.parseDouble(parts[1].trim());
                    return (min + max) / 2.0;
                }
            }

            // 处理可能包含非数字字符的情况
            // 提取数字部分
            String numericPart = cleanScore.replaceAll("[^0-9.]", "");
            if (!numericPart.isEmpty()) {
                return Double.parseDouble(numericPart);
            }

            return 0.0;
        } catch (NumberFormatException e) {
            log.debug("无法解析分数字符串: {}", scoreStr);
            return 0.0;
        }
    }

    /**
     * 保存推荐结果
     */
    private void saveRecommendationResult(Long userId, Map<String, Map<String, List<MajorInfo>>> groupedMajors) {
        try {
            // 构建树形结构
            CeeMajorTreeVO treeVO = new CeeMajorTreeVO();
            List<CeeMajorTreeVO.CategoryNode> categoryNodes = new ArrayList<>();

            // 遍历学科门类
            for (Map.Entry<String, Map<String, List<MajorInfo>>> categoryEntry : groupedMajors.entrySet()) {
                String category = categoryEntry.getKey();
                Map<String, List<MajorInfo>> subCategoryMap = categoryEntry.getValue();

                // 检查该学科门类下是否有包含专业的子类
                boolean hasData = subCategoryMap.values().stream().anyMatch(majors -> !majors.isEmpty());
                if (!hasData) {
                    continue;
                }

                CeeMajorTreeVO.CategoryNode categoryNode = new CeeMajorTreeVO.CategoryNode();
                categoryNode.setId(category);
                categoryNode.setName(category);
                categoryNode.setLoaded(true);

                List<CeeMajorTreeVO.SubCategoryNode> subCategoryNodes = new ArrayList<>();

                // 构建子类节点
                for (Map.Entry<String, List<MajorInfo>> subCategoryEntry : subCategoryMap.entrySet()) {
                    String subCategory = subCategoryEntry.getKey();
                    List<MajorInfo> majors = subCategoryEntry.getValue();

                    if (majors.isEmpty()) {
                        continue;
                    }

                    CeeMajorTreeVO.SubCategoryNode subCategoryNode = new CeeMajorTreeVO.SubCategoryNode();
                    subCategoryNode.setId(subCategory);
                    subCategoryNode.setName(subCategory);

                    List<CeeMajorTreeVO.MajorNode> majorNodes = new ArrayList<>();

                    // 构建专业节点
                    for (MajorInfo major : majors) {
                        CeeMajorTreeVO.MajorNode majorNode = new CeeMajorTreeVO.MajorNode();
                        majorNode.setId(major.getId());
                        majorNode.setName(major.getName());
                        majorNode.setCode(major.getCode());
                        majorNode.setEducationLevel(major.getEducationLevel());
                        majorNode.setIsRecommended(major.getIsRecommended());
                        majorNode.setCareerDirection(major.getCareerDirection());
                        majorNode.setMajorIntroduction(major.getMajorIntroduction());
                        majorNode.setGraduateScale(major.getGraduateScale());
                        majorNode.setMaleFemaleRatio(major.getMaleFemaleRatio());
                        majorNode.setRecommendSchools(major.getRecommendSchools());
                        majorNode.setCourses(major.getCourses());
                        majorNodes.add(majorNode);
                    }

                    subCategoryNode.setChildren(majorNodes);
                    subCategoryNodes.add(subCategoryNode);
                }

                categoryNode.setChildren(subCategoryNodes);
                categoryNodes.add(categoryNode);
            }

            treeVO.setCategories(categoryNodes);

            // 将树形结构转换为JSON字符串
            ObjectMapper objectMapper = new ObjectMapper();
            String recommendedMajorsJson = objectMapper.writeValueAsString(treeVO);

            // 更新用户的推荐专业字段
            AdminUserDO majorUpdateObj = new AdminUserDO();
            majorUpdateObj.setId(userId);
            majorUpdateObj.setRecommendedMajors(recommendedMajorsJson);
            userMapper.updateById(majorUpdateObj);

            int totalMajors = categoryNodes.stream()
                    .flatMap(c -> c.getChildren().stream())
                    .mapToInt(s -> s.getChildren().size())
                    .sum();

            log.info("用户ID {}更新了{}个推荐专业", userId, totalMajors);
        } catch (Exception e) {
            log.error("保存用户ID {}的推荐结果失败", userId, e);
        }
    }

    /**
     * 保存无推荐结果（-1）
     */
    private void saveNoRecommendationResult(Long userId) {
        try {
            // 更新用户的推荐专业字段为-1
            AdminUserDO majorUpdateObj = new AdminUserDO();
            majorUpdateObj.setId(userId);
            majorUpdateObj.setRecommendedMajors("-1");
            userMapper.updateById(majorUpdateObj);

            log.info("用户ID {}未找到任何专业推荐，已保存结果为-1", userId);
        } catch (Exception e) {
            log.error("保存用户ID {}的无推荐结果失败", userId, e);
        }
    }

    /**
     * 记录线程池状态，用于监控任务执行情况
     */
    private void logThreadPoolStatus() {
        if (MAJOR_RECOMMENDATION_EXECUTOR instanceof ThreadPoolExecutor) {
            ThreadPoolExecutor executor = MAJOR_RECOMMENDATION_EXECUTOR;
            log.info("专业推荐线程池状态: 活跃线程[{}], 核心线程[{}], 最大线程[{}], 队列大小[{}], 已完成任务[{}], 总任务[{}], 正在执行任务[{}]",
                    executor.getActiveCount(),
                    executor.getCorePoolSize(),
                    executor.getMaximumPoolSize(),
                    executor.getQueue().size(),
                    executor.getCompletedTaskCount(),
                    executor.getTaskCount(),
                    MAJOR_RECOMMENDATION_TASKS.size());
        }
    }

    /**
     * 重构第一步：从招生计划表筛选符合条件的数据
     * @param province 省份
     * @param userSubjects 用户选科
     * @param typeName 类型名称
     * @return 符合条件的招生计划列表
     */
    private List<CollegeEnrollmentPlanDO> filterEnrollmentPlansForUser(String province, Set<String> userSubjects, String typeName) {
        try {
            // 基础查询条件：省份和年份
            List<CollegeEnrollmentPlanDO> enrollmentPlans = collegeEnrollmentPlanMapper
                    .selectListByProvinceAndYearAndType(province, 2024,typeName);

            log.info("基础查询（省份: {}, 年份: 2024）得到 {} 条招生计划数据", province, enrollmentPlans.size());

            if (enrollmentPlans.isEmpty()) {
                log.warn("基础查询未找到任何招生计划数据，省份: {}", province);
                return enrollmentPlans;
            }

            // 过滤选科要求
            if (userSubjects != null && !userSubjects.isEmpty()) {
                int beforeSubjectFilter = enrollmentPlans.size();
                List<String> subjectsList = new ArrayList<>(userSubjects);
                enrollmentPlans = filterEnrollmentPlansBySubjects(enrollmentPlans, subjectsList);
                log.info("选科筛选：{} -> {}，用户选科: {}", beforeSubjectFilter, enrollmentPlans.size(), userSubjects);

                if (enrollmentPlans.isEmpty()) {
                    log.warn("选科筛选后无剩余数据，用户选科: {}", userSubjects);
                }
            }

            // 过滤类型名称（如果有）
            if (typeName != null && !typeName.trim().isEmpty()) {
                int beforeTypeFilter = enrollmentPlans.size();
                enrollmentPlans = enrollmentPlans.stream()
                        .filter(plan -> {
                            String planType = plan.getType();
                            if (planType == null) {
                                return false;
                            }
                            // 精确匹配或包含匹配
                            return typeName.equals(planType) ||
                                   planType.contains(typeName) ||
                                   typeName.contains(planType);
                        })
                        .collect(Collectors.toList());
                log.info("类型筛选：{} -> {}，过滤条件: {}", beforeTypeFilter, enrollmentPlans.size(), typeName);
            }

            return enrollmentPlans;

        } catch (Exception e) {
            log.error("从招生计划表筛选数据时发生错误", e);
            return new ArrayList<>();
        }
    }

    /**
     * 重构第二步：根据招生计划结果查询专业录取分数线表
     * @param enrollmentPlans 符合条件的招生计划列表
     * @param province 省份
     * @param minScore 最低分数
     * @param maxScore 最高分数
     * @param typeName 类型名称
     * @return 专业录取信息列表
     */
    private List<MajorAdmissionInfo> queryAdmissionScoresByEnrollmentPlansForUser(List<CollegeEnrollmentPlanDO> enrollmentPlans,
                                                                                   String province, int minScore, int maxScore, String typeName) {
        if (enrollmentPlans == null || enrollmentPlans.isEmpty()) {
            return new ArrayList<>();
        }

        // 提取学校UUID和专业名称
        List<String> schoolUUIDs = new ArrayList<>();
        List<String> majorNames = new ArrayList<>();

        for (CollegeEnrollmentPlanDO plan : enrollmentPlans) {
            if (plan.getSchoolUuid() != null && !plan.getSchoolUuid().trim().isEmpty()) {
                schoolUUIDs.add(plan.getSchoolUuid());
            }
            if (plan.getCollegeMajorName() != null && !plan.getCollegeMajorName().trim().isEmpty()) {
                majorNames.add(plan.getCollegeMajorName());
            }
        }

        // 去重
        schoolUUIDs = schoolUUIDs.stream().distinct().collect(Collectors.toList());
        majorNames = majorNames.stream().distinct().collect(Collectors.toList());

        log.info("提取到 {} 个学校UUID，{} 个专业名称", schoolUUIDs.size(), majorNames.size());

        try {
            // 批量查询专业录取分数数据
            List<MajorAdmissionDO> admissionDOList = majorAdmissionMapper
                    .batchSelectAdmissionScoresSimple(schoolUUIDs, majorNames, 2024, typeName, province);

            log.info("批量查询得到 {} 条专业录取分数数据", admissionDOList.size());

            // 过滤分数范围
            List<MajorAdmissionDO> filteredAdmissions = admissionDOList.stream()
                    .filter(admission -> {
                        try {
                            String lowestScore = admission.getLowestScore();
                            if (lowestScore != null && !lowestScore.trim().isEmpty()) {
                                int score = Integer.parseInt(lowestScore.trim());
                                return score >= minScore && score <= maxScore;
                            }
                        } catch (NumberFormatException e) {
                            log.debug("无法解析分数: {}", admission.getLowestScore());
                        }
                        return false;
                    })
                    .collect(Collectors.toList());

            log.info("分数范围过滤后剩余 {} 条数据", filteredAdmissions.size());

            // 转换为 MajorAdmissionInfo 并关联招生计划信息
            List<MajorAdmissionInfo> admissionInfos = new ArrayList<>();
            for (MajorAdmissionDO admission : filteredAdmissions) {
                MajorAdmissionInfo info = convertToMajorAdmissionInfo(admission);

                // 从招生计划中获取额外信息
                CollegeEnrollmentPlanDO matchedPlan = findMatchingEnrollmentPlanForUser(enrollmentPlans, admission);
                if (matchedPlan != null) {
                    // 将招生计划信息转换为 CollegeEnrollmentPlanInfo 并设置到 enrollmentPlanData
                    CollegeEnrollmentPlanInfo planInfo = convertToCollegeEnrollmentPlanInfo(matchedPlan);
                    info.setEnrollmentPlanData(Arrays.asList(planInfo));

                    // 更新 batchName（如果招生计划中有更准确的信息）
                    if (matchedPlan.getBatchName() != null && !matchedPlan.getBatchName().trim().isEmpty()) {
                        info.setBatchName(matchedPlan.getBatchName());
                    }
                }

                admissionInfos.add(info);
            }

            log.info("最终转换得到 {} 条专业录取信息", admissionInfos.size());
            return admissionInfos;

        } catch (Exception e) {
            log.error("根据招生计划查询专业录取分数线时发生错误", e);
            return new ArrayList<>();
        }
    }

    /**
     * 查找匹配的招生计划（为用户推荐使用）
     * @param enrollmentPlans 招生计划列表
     * @param admission 专业录取数据
     * @return 匹配的招生计划，没有则返回null
     */
    private CollegeEnrollmentPlanDO findMatchingEnrollmentPlanForUser(List<CollegeEnrollmentPlanDO> enrollmentPlans, MajorAdmissionDO admission) {
        for (CollegeEnrollmentPlanDO plan : enrollmentPlans) {
            // 匹配学校UUID和专业名称
            if (Objects.equals(plan.getSchoolUuid(), admission.getSchoolUuid())
                    && isMajorNameMatchForUser(plan.getCollegeMajorName(), admission.getMajorName())) {
                return plan;
            }
        }
        return null;
    }

    /**
     * 检查专业名称是否匹配（为用户推荐使用）
     * @param planMajorName 招生计划中的专业名称
     * @param admissionMajorName 录取数据中的专业名称
     * @return 是否匹配
     */
    private boolean isMajorNameMatchForUser(String planMajorName, String admissionMajorName) {
        if (planMajorName == null || admissionMajorName == null) {
            return false;
        }

        // 精确匹配
        if (planMajorName.equals(admissionMajorName)) {
            return true;
        }

        // 模糊匹配（去除空格和特殊字符后比较）
        String cleanPlanName = planMajorName.replaceAll("[\\s\\(\\)【】《》]", "");
        String cleanAdmissionName = admissionMajorName.replaceAll("[\\s\\(\\)【】《》]", "");

        return cleanPlanName.equals(cleanAdmissionName) ||
               cleanPlanName.contains(cleanAdmissionName) ||
               cleanAdmissionName.contains(cleanPlanName);
    }

    /**
     * 根据选科要求过滤招生计划（为用户推荐使用）
     * @param enrollmentPlans 招生计划列表
     * @param userSubjects 用户选科
     * @return 过滤后的招生计划列表
     */
    private List<CollegeEnrollmentPlanDO> filterEnrollmentPlansBySubjects(List<CollegeEnrollmentPlanDO> enrollmentPlans, List<String> userSubjects) {
        if (userSubjects == null || userSubjects.isEmpty()) {
            return enrollmentPlans;
        }

        List<CollegeEnrollmentPlanDO> filteredPlans = new ArrayList<>();

        for (CollegeEnrollmentPlanDO plan : enrollmentPlans) {
            String courseSelectionRequirements = plan.getCourseSelectionRequirements();

            // 如果没有选科要求，则认为符合条件
            if (courseSelectionRequirements == null || courseSelectionRequirements.trim().isEmpty()
                    || "不限".equals(courseSelectionRequirements) || "无".equals(courseSelectionRequirements)) {
                filteredPlans.add(plan);
                continue;
            }

            // 检查用户选科是否满足要求
            Set<String> userSubjectsSet = new HashSet<>(userSubjects);
            if (checkSubjectRequirements(userSubjectsSet, courseSelectionRequirements)) {
                filteredPlans.add(plan);
            }
        }

        return filteredPlans;
    }

    /**
     * 将 CollegeEnrollmentPlanDO 转换为 CollegeEnrollmentPlanInfo（为用户推荐使用）
     * @param planDO 招生计划 DO 对象
     * @return 招生计划 Info 对象
     */
    private CollegeEnrollmentPlanInfo convertToCollegeEnrollmentPlanInfo(CollegeEnrollmentPlanDO planDO) {
        if (planDO == null) {
            return null;
        }

        CollegeEnrollmentPlanInfo planInfo = new CollegeEnrollmentPlanInfo();

        planInfo.setProvinceName(planDO.getProvinceName());
        planInfo.setSchoolUuid(planDO.getSchoolUuid());
        planInfo.setSchoolName(planDO.getSchoolName());
        planInfo.setCollegeMajorName(planDO.getCollegeMajorName());
        planInfo.setCollegeMajorCode(planDO.getCollegeMajorCode());
        planInfo.setYear(planDO.getYear());
        planInfo.setEnrollmentNumbers(planDO.getEnrollmentNumbers());
        planInfo.setInSchoolYears(planDO.getInSchoolYears());
        planInfo.setClassOne(planDO.getClassOne());
        planInfo.setClassTwo(planDO.getClassTwo());
        planInfo.setBatchName(planDO.getBatchName());
        planInfo.setType(planDO.getType());
        planInfo.setCourseSelectionRequirements(planDO.getCourseSelectionRequirements());

        // 专业组相关字段
        planInfo.setSpecialGroup(planDO.getSpecialGroup());
        planInfo.setSpecialCode(planDO.getSpecialCode());
        planInfo.setSpecialGroupName(planDO.getSpecialGroupName());

        return planInfo;
    }

    /**
     * 第一步：根据专业录取分数线筛选
     * @param province 省份
     * @param minScore 最低分数
     * @param maxScore 最高分数
     * @param typeName 类型名称
     * @return 专业录取信息列表
     */
    private List<MajorAdmissionInfo> queryAdmissionScoresByScoreRangeForUser(String province, int minScore, int maxScore, String typeName) {
        try {
            List<MajorAdmissionDO> admissionDOList;

            // 根据是否有typeName选择不同的查询方法
            if (typeName != null && !typeName.trim().isEmpty()) {
                admissionDOList = majorAdmissionService.getMajorAdmissionByProvinceYearScoreRangeAndType(
                        province, 2024, minScore, maxScore, typeName);
            } else {
                admissionDOList = majorAdmissionService.getMajorAdmissionByProvinceYearAndScoreRange(
                        province, 2024, minScore, maxScore);
            }

            log.info("根据分数范围查询得到 {} 条专业录取数据", admissionDOList.size());

            // 转换为 MajorAdmissionInfo 列表
            List<MajorAdmissionInfo> admissionInfos = new ArrayList<>();
            for (MajorAdmissionDO admissionDO : admissionDOList) {
                MajorAdmissionInfo info = convertToMajorAdmissionInfo(admissionDO);
                if (info != null) {
                    admissionInfos.add(info);
                }
            }

            log.info("转换得到 {} 条专业录取信息", admissionInfos.size());
            return admissionInfos;

        } catch (Exception e) {
            log.error("根据分数范围查询专业录取分数线时发生错误", e);
            return new ArrayList<>();
        }
    }

    /**
     * 第二步：根据招生计划筛选（多线程优化版本）
     * 优化策略：使用多线程并行查询招生计划数据，只返回有招生计划的专业
     * @param admissionList 专业录取信息列表
     * @param province 省份
     * @param userSubjects 用户选科
     * @param typeName 类型名称
     * @return 过滤后的专业录取信息列表
     */
    private List<MajorAdmissionInfo> filterAdmissionsByEnrollmentPlansForUser(List<MajorAdmissionInfo> admissionList,
                                                                               String province, Set<String> userSubjects, String typeName) {
        if (admissionList == null || admissionList.isEmpty()) {
            return new ArrayList<>();
        }

        // 如果数据量较小，使用单线程处理
        if (admissionList.size() <= 50) {
            return filterAdmissionsByEnrollmentPlansForUserSingleThread(admissionList, province, userSubjects, typeName);
        }

        try {
            // 使用多线程处理
            return filterAdmissionsByEnrollmentPlansForUserMultiThread(admissionList, province, userSubjects, typeName);
        } catch (Exception e) {
            log.error("多线程处理招生计划筛选失败，回退到单线程处理", e);
            return filterAdmissionsByEnrollmentPlansForUserSingleThread(admissionList, province, userSubjects, typeName);
        }
    }

    /**
     * 多线程版本：根据招生计划筛选专业录取数据
     * @param admissionList 专业录取信息列表
     * @param province 省份
     * @param userSubjects 用户选科
     * @param typeName 类型名称
     * @return 过滤后的专业录取信息列表
     */
    private List<MajorAdmissionInfo> filterAdmissionsByEnrollmentPlansForUserMultiThread(List<MajorAdmissionInfo> admissionList,
                                                                                          String province, Set<String> userSubjects, String typeName) {
        long startTime = System.currentTimeMillis();
        log.info("开始多线程处理 {} 个专业录取数据的招生计划查询", admissionList.size());

        // 线程安全的结果集合
        List<MajorAdmissionInfo> filteredList = Collections.synchronizedList(new ArrayList<>());

        // 线程安全的缓存
        Map<String, List<CollegeEnrollmentPlanDO>> enrollmentPlanCache = new ConcurrentHashMap<>();

        // 统计计数器
        AtomicInteger matchedCount = new AtomicInteger(0);
        AtomicInteger notMatchedCount = new AtomicInteger(0);

        List<String> userSubjectsList = userSubjects != null ? new ArrayList<>(userSubjects) : null;

        // 计算线程数：根据CPU核心数和数据量动态调整
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        int threadCount = Math.min(Math.max(2, availableProcessors / 2), 8); // 最少2个，最多8个线程

        // 计算每个线程处理的数据量
        int batchSize = Math.max(1, admissionList.size() / threadCount);

        log.info("使用 {} 个线程处理数据，每个线程处理约 {} 条记录", threadCount, batchSize);

        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(threadCount, r -> {
            Thread t = new Thread(r, "enrollment-plan-query-" + System.currentTimeMillis());
            t.setDaemon(true);
            return t;
        });

        try {
            List<CompletableFuture<Void>> futures = new ArrayList<>();

            // 分批处理数据
            for (int i = 0; i < admissionList.size(); i += batchSize) {
                int endIndex = Math.min(i + batchSize, admissionList.size());
                List<MajorAdmissionInfo> batch = admissionList.subList(i, endIndex);

                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    processBatchEnrollmentPlans(batch, province, userSubjectsList, typeName,
                                              enrollmentPlanCache, filteredList, matchedCount, notMatchedCount);
                }, executor);

                futures.add(future);
            }

            // 等待所有任务完成
            CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
            allFutures.get(5, TimeUnit.MINUTES); // 最多等待5分钟

            long endTime = System.currentTimeMillis();
            log.info("多线程招生计划过滤完成 - 匹配: {}, 未匹配: {}, 最终保留: {} 条专业录取数据, 缓存大小: {} 个, 耗时: {}ms",
                    matchedCount.get(), notMatchedCount.get(), filteredList.size(),
                    enrollmentPlanCache.size(), (endTime - startTime));

            return new ArrayList<>(filteredList);

        } catch (TimeoutException e) {
            log.error("多线程处理超时，部分数据可能未完成处理", e);
            return new ArrayList<>(filteredList);
        } catch (InterruptedException e) {
            log.error("多线程处理被中断", e);
            Thread.currentThread().interrupt();
            return new ArrayList<>(filteredList);
        } catch (ExecutionException e) {
            log.error("多线程处理执行异常", e);
            return new ArrayList<>(filteredList);
        } catch (Exception e) {
            log.error("多线程处理过程中发生异常", e);
            return new ArrayList<>(filteredList);
        } finally {
            executor.shutdown();
            try {
                if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                executor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * 批处理方法：处理一批专业录取数据的招生计划查询
     * @param batch 一批专业录取数据
     * @param province 省份
     * @param userSubjectsList 用户选科列表
     * @param typeName 类型名称
     * @param enrollmentPlanCache 招生计划缓存
     * @param filteredList 过滤后的结果列表
     * @param matchedCount 匹配计数器
     * @param notMatchedCount 未匹配计数器
     */
    private void processBatchEnrollmentPlans(List<MajorAdmissionInfo> batch, String province,
                                           List<String> userSubjectsList, String typeName,
                                           Map<String, List<CollegeEnrollmentPlanDO>> enrollmentPlanCache,
                                           List<MajorAdmissionInfo> filteredList,
                                           AtomicInteger matchedCount, AtomicInteger notMatchedCount) {
        for (MajorAdmissionInfo admission : batch) {
            try {
                String schoolName = admission.getSchoolName();
                String majorName = admission.getMajorName();

                if (schoolName == null || majorName == null) {
                    log.debug("跳过无效的录取数据：学校名称或专业名称为空");
                    notMatchedCount.incrementAndGet();
                    continue;
                }

                // 构建缓存键
                String cacheKey = schoolName + ":" + majorName;

                List<CollegeEnrollmentPlanDO> matchingPlans;

                // 检查缓存（线程安全）
                if (enrollmentPlanCache.containsKey(cacheKey)) {
                    matchingPlans = enrollmentPlanCache.get(cacheKey);
                    log.debug("从缓存获取招生计划：{}", cacheKey);
                } else {
                    // 为当前专业查询招生计划
                    matchingPlans = collegeEnrollmentPlanMapper.selectBySchoolAndMajorWithFilters(
                            schoolName, majorName, province, 2024, userSubjectsList, typeName);

                    // 缓存结果（线程安全）
                    enrollmentPlanCache.put(cacheKey, matchingPlans);
                    log.debug("查询并缓存招生计划：{} -> {} 条记录", cacheKey, matchingPlans.size());
                }

                // 只处理有招生计划的专业
                if (!matchingPlans.isEmpty()) {
                    // 找到匹配的招生计划，选择第一个作为主要计划
                    CollegeEnrollmentPlanDO primaryPlan = matchingPlans.get(0);

                    // 设置招生计划数据
                    List<CollegeEnrollmentPlanInfo> planInfoList = new ArrayList<>();
                    for (CollegeEnrollmentPlanDO plan : matchingPlans) {
                        planInfoList.add(convertToCollegeEnrollmentPlanInfo(plan));
                    }
                    admission.setEnrollmentPlanData(planInfoList);

                    // 更新批次信息（如果招生计划中有更准确的信息）
                    if (primaryPlan.getBatchName() != null && !primaryPlan.getBatchName().trim().isEmpty()) {
                        admission.setBatchName(primaryPlan.getBatchName());
                    }

                    filteredList.add(admission);
                    matchedCount.incrementAndGet();

                    log.debug("匹配成功：{} -> {} 条招生计划", cacheKey, matchingPlans.size());
                } else {
                    // 没有招生计划的专业不添加到结果中
                    log.debug("未找到匹配的招生计划，剔除专业：{}", cacheKey);
                    notMatchedCount.incrementAndGet();
                }
            } catch (Exception e) {
                log.error("处理专业录取数据时发生异常：{} - {}", admission.getSchoolName(), admission.getMajorName(), e);
                notMatchedCount.incrementAndGet();
            }
        }
    }

    /**
     * 单线程版本：根据招生计划筛选专业录取数据（作为备用方案）
     * @param admissionList 专业录取信息列表
     * @param province 省份
     * @param userSubjects 用户选科
     * @param typeName 类型名称
     * @return 过滤后的专业录取信息列表
     */
    private List<MajorAdmissionInfo> filterAdmissionsByEnrollmentPlansForUserSingleThread(List<MajorAdmissionInfo> admissionList,
                                                                                          String province, Set<String> userSubjects, String typeName) {
        try {
            List<MajorAdmissionInfo> filteredList = new ArrayList<>();
            int matchedCount = 0;
            int notMatchedCount = 0;

            // 缓存已查询的学校-专业组合，避免重复查询
            Map<String, List<CollegeEnrollmentPlanDO>> enrollmentPlanCache = new HashMap<>();
            List<String> userSubjectsList = userSubjects != null ? new ArrayList<>(userSubjects) : null;

            log.info("开始单线程处理 {} 个专业录取数据查询对应的招生计划", admissionList.size());

            for (MajorAdmissionInfo admission : admissionList) {
                String schoolName = admission.getSchoolName();
                String majorName = admission.getMajorName();

                if (schoolName == null || majorName == null) {
                    log.debug("跳过无效的录取数据：学校名称或专业名称为空");
                    notMatchedCount++;
                    continue;
                }

                // 构建缓存键
                String cacheKey = schoolName + ":" + majorName;

                List<CollegeEnrollmentPlanDO> matchingPlans;

                // 检查缓存
                if (enrollmentPlanCache.containsKey(cacheKey)) {
                    matchingPlans = enrollmentPlanCache.get(cacheKey);
                    log.debug("从缓存获取招生计划：{}", cacheKey);
                } else {
                    // 为当前专业查询招生计划，使用优化的查询方法（支持专业名称差异匹配）
                    matchingPlans = collegeEnrollmentPlanMapper.selectBySchoolAndMajorWithFilters(
                            schoolName, majorName, province, 2024, userSubjectsList, typeName);

                    // 缓存结果
                    enrollmentPlanCache.put(cacheKey, matchingPlans);
                    log.debug("查询并缓存招生计划：{} -> {} 条记录", cacheKey, matchingPlans.size());
                }

                // 只处理有招生计划的专业
                if (!matchingPlans.isEmpty()) {
                    // 找到匹配的招生计划，选择第一个作为主要计划
                    CollegeEnrollmentPlanDO primaryPlan = matchingPlans.get(0);

                    // 设置招生计划数据
                    List<CollegeEnrollmentPlanInfo> planInfoList = new ArrayList<>();
                    for (CollegeEnrollmentPlanDO plan : matchingPlans) {
                        planInfoList.add(convertToCollegeEnrollmentPlanInfo(plan));
                    }
                    admission.setEnrollmentPlanData(planInfoList);

                    // 更新批次信息（如果招生计划中有更准确的信息）
                    if (primaryPlan.getBatchName() != null && !primaryPlan.getBatchName().trim().isEmpty()) {
                        admission.setBatchName(primaryPlan.getBatchName());
                    }

                    filteredList.add(admission);
                    matchedCount++;

                    log.debug("匹配成功：{} -> {} 条招生计划", cacheKey, matchingPlans.size());
                } else {
                    // 没有招生计划的专业不添加到结果中
                    log.debug("未找到匹配的招生计划，剔除专业：{}", cacheKey);
                    notMatchedCount++;
                }
            }

            log.info("单线程招生计划过滤完成 - 匹配: {}, 未匹配: {}, 最终保留: {} 条专业录取数据, 缓存大小: {} 个",
                    matchedCount, notMatchedCount, filteredList.size(), enrollmentPlanCache.size());

            return filteredList;

        } catch (Exception e) {
            log.error("根据招生计划筛选专业录取数据时发生错误", e);
            return new ArrayList<>();
        }
    }

    /**
     * 第二步：根据招生计划筛选（原版本，作为备用）
     * @param admissionList 专业录取信息列表
     * @param province 省份
     * @param userSubjects 用户选科
     * @param typeName 类型名称
     * @return 过滤后的专业录取信息列表
     */
    private List<MajorAdmissionInfo> filterAdmissionsByEnrollmentPlansForUserOriginal(List<MajorAdmissionInfo> admissionList,
                                                                               String province, Set<String> userSubjects, String typeName) {
        if (admissionList == null || admissionList.isEmpty()) {
            return new ArrayList<>();
        }

        try {
            // 查询招生计划数据
            List<CollegeEnrollmentPlanDO> enrollmentPlans = filterEnrollmentPlansForUser(province, userSubjects, typeName);
            log.info("查询到 {} 条符合条件的招生计划", enrollmentPlans.size());

            if (enrollmentPlans.isEmpty()) {
                log.warn("未找到符合条件的招生计划，返回空列表");
                return new ArrayList<>();
            }

            // 构建有效的学校-专业组合集合（同时处理原始名称和清理后的名称）
            Set<String> validCombinations = new HashSet<>();
            for (CollegeEnrollmentPlanDO plan : enrollmentPlans) {
                String schoolName = plan.getSchoolName();
                String originalMajorName = plan.getCollegeMajorName();

                // 添加原始专业名称组合
                if (originalMajorName != null) {
                    validCombinations.add(schoolName + ":" + originalMajorName);
                }

                // 添加去除括号后的专业名称组合
                String cleanMajorName = removeBrackets(originalMajorName);
                if (cleanMajorName != null && !cleanMajorName.equals(originalMajorName)) {
                    validCombinations.add(schoolName + ":" + cleanMajorName);
                }
            }

            log.info("构建了 {} 个有效的学校-专业组合", validCombinations.size());

            // 过滤专业录取数据
            List<MajorAdmissionInfo> filteredList = new ArrayList<>();
            int matchedCount = 0;
            int notMatchedCount = 0;

            for (MajorAdmissionInfo admission : admissionList) {
                String admissionCombination = admission.getSchoolName() + ":" + admission.getMajorName();
                String cleanAdmissionCombination = admission.getSchoolName() + ":" + removeBrackets(admission.getMajorName());

                // 检查是否匹配（原始名称或清理后的名称）
                boolean isMatched = validCombinations.contains(admissionCombination) ||
                                   validCombinations.contains(cleanAdmissionCombination);

                if (isMatched) {
                    // 查找匹配的招生计划并设置招生计划信息
                    CollegeEnrollmentPlanDO matchingPlan = findMatchingEnrollmentPlan(enrollmentPlans, admission);
                    if (matchingPlan != null) {
                        // 设置招生计划数据
                        List<CollegeEnrollmentPlanInfo> planInfoList = new ArrayList<>();
                        planInfoList.add(convertToCollegeEnrollmentPlanInfo(matchingPlan));
                        admission.setEnrollmentPlanData(planInfoList);
                        filteredList.add(admission);
                        matchedCount++;
                    } else {
                        log.debug("组合匹配但未找到具体招生计划: {}", admissionCombination);
                        notMatchedCount++;
                    }
                } else {
                    log.debug("未匹配的录取数据组合: {}", admissionCombination);
                    notMatchedCount++;
                }
            }

            log.info("原版招生计划过滤结果 - 匹配: {}, 未匹配: {}, 最终保留: {} 条专业录取数据",
                    matchedCount, notMatchedCount, filteredList.size());
            return filteredList;

        } catch (Exception e) {
            log.error("根据招生计划筛选专业录取数据时发生错误", e);
            return new ArrayList<>();
        }
    }

    /**
     * 查找匹配的招生计划
     * @param enrollmentPlans 招生计划列表
     * @param admission 专业录取信息
     * @return 匹配的招生计划，没有则返回null
     */
    private CollegeEnrollmentPlanDO findMatchingEnrollmentPlan(List<CollegeEnrollmentPlanDO> enrollmentPlans, MajorAdmissionInfo admission) {
        for (CollegeEnrollmentPlanDO plan : enrollmentPlans) {
            // 匹配学校名称和专业名称
            if (Objects.equals(plan.getSchoolName(), admission.getSchoolName())
                    && isMajorNameMatchForUser(plan.getCollegeMajorName(), admission.getMajorName())) {
                return plan;
            }
        }
        return null;
    }

    /**
     * 将 MajorAdmissionDO 转换为 MajorAdmissionInfo（为用户推荐使用）
     * @param admissionDO MajorAdmissionDO 对象
     * @return MajorAdmissionInfo 对象
     */
    private MajorAdmissionInfo convertToMajorAdmissionInfo(MajorAdmissionDO admissionDO) {
        if (admissionDO == null) {
            return null;
        }

        MajorAdmissionInfo info = new MajorAdmissionInfo();
        info.setProvinceName(admissionDO.getProvinceName());
        info.setSchoolUUID(admissionDO.getSchoolUuid());
        info.setSchoolName(admissionDO.getSchoolName());
        info.setMajorName(admissionDO.getMajorName());
        info.setMajorCode(admissionDO.getMajorCode());
        info.setYear(admissionDO.getYear());
        info.setHighScore(admissionDO.getHighScore());
        info.setAverageScore(admissionDO.getAverageScore());
        info.setLowestScore(admissionDO.getLowestScore());
        info.setLowestSection(admissionDO.getLowestSection());
        info.setBatchName(admissionDO.getBatchName());
        info.setTypeName(admissionDO.getTypeName());
        info.setProScore(admissionDO.getProScore());
        info.setSubjectSelection(admissionDO.getSubjectSelection());
        info.setSubjectGroup(admissionDO.getSubjectGroup());
        info.setMajorStandardCode(admissionDO.getMajorStandardCode());
        return info;
    }

}
